NC20470. [ZJOI2007]HIDE 捉迷藏
描述
输入描述
第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。
接下来N-1行每行两个整数a, b,表示房间a与房间b之间有一条走廊相连。
接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如上文所示。
输出描述
对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。
若只有一个房间是关着灯的,输出0;若所有房间的灯都开着,输出-1。
示例1
输入:
8 1 2 2 3 3 4 3 5 3 6 6 7 6 8 7 G C 1 G C 2 G C 1 G
输出:
4 3 3 4
C++(g++ 7.5.0) 解法, 执行用时: 3264ms, 内存消耗: 179784K, 提交时间: 2022-09-22 20:38:44
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <queue> using namespace std ; using ll = long long ; using pii = pair<int,int> ; const int N = 4e5 + 100 , M = 2 * N ; const int INF = N ; // 题目是要询问任意两个关着灯之间的最长距离 // 那么我们进行维护,对于每一个重心来说,我们进行对每一个儿子维护一个最大值 // 将与重心直接相连接的子树中最大值插入当前重心所维护的信息中 // 然后为了方便,我们直接相连的子树肯定是另一个,所以我们直接进行计算 // 然后我们还使用一个变量来维护全局的最大值 int n,m ; int h[N],e[M],ne[M],idx ; int sz[N],dist[N] ; bool st[N],state[N] ; struct Dui{ priority_queue<int> q,del ; void insert(int x){ q.push(x) ; } void del_c(int x){ del.push(x) ; } int get_max(){ while(!q.empty() && !del.empty() && q.top() == del.top()) q.pop(),del.pop() ; if(q.empty()) return -INF ; return q.top() ; } int get_mx2(){ int tot = get_max() ; if(tot == -INF) return -INF ; q.pop() ; int ans = get_max() ; q.push(tot) ; return ans ; } }; int divfa[N] ; Dui global ; // 存储全局的信息 Dui zz[N] ; // 存储当前连通块的最大值 Dui grz[N] ; // 存储与重心直接相连接的所有子树的最大值 struct Info{ int dist,gr ; }; vector<Info> po[N] ; void add(int a,int b){ e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ; } int getsz(int u,int fa){ int tot = 1 ; for(int i = h[u] ; ~ i ; i = ne[i]){ int j = e[i] ; if(j == fa || st[j]) continue ; tot += getsz(j,u) ; } return tot ; } int getgravity(int u,int fa,int sum){ int gr = -1,mx = 0 ; sz[u] = 1 ; for(int i = h[u] ; ~ i ; i = ne[i]){ int j = e[i] ; if(j == fa || st[j]) continue ; int nx = getgravity(j,u,sum) ; if(nx != -1) gr = nx ; sz[u] += sz[j] ; mx = max(mx,sz[j]) ; } mx = max(mx,sum - sz[u]) ; if(2 * mx <= sum) gr = u ; return gr ; } void dfs(int u,int fa,int dist,int gr){ po[u].push_back({dist,gr}) ; zz[gr].insert(dist) ; for(int i = h[u] ;~ i ; i = ne[i]){ int j = e[i] ; if(j == fa || st[j]) continue ; dfs(j,u,dist+1,gr) ; } } void divtree(int u,int fa){ int tot = getsz(u,-1) ; int gr = getgravity(u,-1,tot) ; divfa[gr] = fa ; grz[gr].insert(0) ; // 插入当前节点 if(fa != -1){ dfs(u,-1,1,gr) ; grz[fa].insert(zz[gr].get_max()) ; } st[gr] = 1 ; for(int i = h[gr] ; ~ i ; i = ne[i]){ int j = e[i] ; if(j == fa || st[j]) continue ; divtree(j,gr) ; } global.insert(grz[gr].get_max() + grz[gr].get_mx2()) ; } int main(){ scanf("%d",&n) ; memset(h,-1,sizeof h) ; for(int i = 1 ; i <= n - 1 ; i ++){ int a,b ; scanf("%d%d",&a,&b) ; add(a,b),add(b,a) ; } divtree(1,-1) ; scanf("%d",&m) ; int cnt = n ; while(m --){ char op ; scanf(" %c",&op) ; if(op == 'G'){ if(cnt == 0) puts("-1") ; else if(cnt == 1) puts("0") ; else printf("%d\n",global.get_max()) ; } else{ int x ; scanf("%d",&x) ; // 改变第x个灯的状态 for(Info t : po[x]){ if(!state[x]){ // 代表原先是关着现在需要打开 // 需要删除这个点 int tot = zz[t.gr].get_max() ; zz[t.gr].del_c(t.dist) ; if(divfa[t.gr] != -1){ global.del_c(grz[divfa[t.gr]].get_max() + grz[divfa[t.gr]].get_mx2()) ; grz[divfa[t.gr]].del_c(tot) ; tot = zz[t.gr].get_max() ; grz[divfa[t.gr]].insert(tot) ; global.insert(grz[divfa[t.gr]].get_max() + grz[divfa[t.gr]].get_mx2()) ; } } else{ // 代表原先是打开,现在需要关闭 int tot = zz[t.gr].get_max() ; zz[t.gr].insert(t.dist) ; if(divfa[t.gr] != -1){ global.del_c(grz[divfa[t.gr]].get_max() + grz[divfa[t.gr]].get_mx2()) ; grz[divfa[t.gr]].del_c(tot) ; tot = zz[t.gr].get_max() ; grz[divfa[t.gr]].insert(tot) ; global.insert(grz[divfa[t.gr]].get_max() + grz[divfa[t.gr]].get_mx2()) ; } } } if(!state[x]){ global.del_c(grz[x].get_max() + grz[x].get_mx2()) ; grz[x].del_c(0) ; global.insert(grz[x].get_max() + grz[x].get_mx2()) ; cnt -- ; state[x] = 1 ; } else{ // 关灯灯 global.del_c(grz[x].get_max() + grz[x].get_mx2()) ; grz[x].insert(0) ; global.insert(grz[x].get_max() + grz[x].get_mx2()) ; cnt ++ ; state[x] = 0 ; } } } return 0 ; }
C++11(clang++ 3.9) 解法, 执行用时: 649ms, 内存消耗: 43348K, 提交时间: 2019-03-09 17:55:33
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<set> #include<ctime> #include<queue> #include<cmath> #include<algorithm> #define inf 1000000000 #define ll long long using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } char ch[10]; int n,q,cnt,tot,black; int last[100005]; int v[300005],pos[100005],c[100005]; struct edge{int to,next;}e[200005]; struct seg{ int l,r,l1,r1,l2,r2,dis,c1,c2; void ini(int x){ dis=-inf; c1=c2=0; if(v[x]==-6)c2=1; if(v[x]==-9)c1=1; if(v[x]>0&&c[v[x]]) l1=l2=r1=r2=0; else l1=l2=r1=r2=-inf; } }t[1200005]; inline int max(int a,int b,int c) { return max(max(a,b),c); } void insert(int u,int v) { e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt; e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt; } void dfs(int x,int fa) { v[++tot]=-6; v[++tot]=x; pos[x]=tot; for(int i=last[x];i;i=e[i].next) if(e[i].to!=fa) dfs(e[i].to,x); v[++tot]=-9; } inline seg merge(seg s1,seg s2) { seg s; int a=s1.c1,b=s1.c2,c=s2.c1,d=s2.c2; s.l=s1.l;s.r=s2.r; s.dis=max(s1.dis,s2.dis); s.dis=max(s.dis,s1.r1+s2.l2,s1.r2+s2.l1); if(b<c)s.c1=a-b+c,s.c2=d; else s.c1=a,s.c2=b-c+d; s.r1=max(s2.r1,s1.r1-c+d,s1.r2+c+d); s.r2=max(s2.r2,s1.r2+c-d); s.l1=max(s1.l1,s2.l1-b+a,s2.l2+b+a); s.l2=max(s1.l2,s2.l2+b-a); return s; } void build(int k,int l,int r) { if(l==r) { t[k].l=l;t[k].r=r; t[k].ini(l); return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); t[k]=merge(t[k<<1],t[k<<1|1]); } void modify(int k,int x) { int l=t[k].l,r=t[k].r; if(l==r){t[k].ini(l);return;} int mid=(l+r)>>1; if(x<=mid)modify(k<<1,x); else modify(k<<1|1,x); t[k]=merge(t[k<<1],t[k<<1|1]); } int main() { black=n=read(); for(int i=1;i<=n;i++)c[i]=1; for(int i=1;i<n;i++) { int u=read(),v=read(); insert(u,v); } dfs(1,0); build(1,1,tot); q=read(); for(int i=1;i<=q;i++) { scanf("%s",ch); if(ch[0]=='C') { int x=read(); if(c[x])black--; else black++; c[x]^=1; modify(1,pos[x]); } else { if(!black)puts("-1"); else if(black==1)puts("0"); else printf("%d\n",t[1].dis); } } return 0; }