SPOJ2666 QTREE4
一道树分治……简直恶心死了……我在调代码的时候只想说:我*************************************************……
昨天听ztc讲了讲树分治,下午心血来潮想写QTREE4……写的是边分治,然后调了一晚上没调出来,后来发现换一个点作根建树就A了(COGS数据弱……)……然而交到vjudge上还是WA,早上接着调结果还调不出来,一怒之下弃坑去写比较简单的动态树分治,感觉点分治挺好写嘛……然后就换用点分治重写QTREE4,调了老半天才调出来……然而vjudge上TLE了= =
这题好像点分治边分治链分治都可以,然而点分治比边分治慢,这根本不科学……看别人写的有点分治也有边分治,然而我边分治实在调不动了……
贴一发点分治的代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=100010; 8 struct binary_heap{ 9 priority_queue<int>q1,q2; 10 void push(int x){q1.push(x);} 11 int top(){ 12 while(!q2.empty()&&q1.top()==q2.top()){ 13 q1.pop(); 14 q2.pop(); 15 } 16 return q1.top(); 17 } 18 int top2(){ 19 int fir=top(); 20 pop(); 21 int sec=top(); 22 push(fir); 23 return sec; 24 } 25 void pop(){ 26 while(!q2.empty()&&q1.top()==q2.top()){ 27 q1.pop(); 28 q2.pop(); 29 } 30 q1.pop(); 31 } 32 void erase(int x){q2.push(x);} 33 int size(){return (int)q1.size()-(int)q2.size();} 34 bool empty(){return !size();} 35 }heap,q[maxn],q1[maxn][20]; 36 void build(int,int,int,int); 37 void dfs_getcenter(int,int,int&); 38 void dfs_getdis(int,int,int); 39 void modify(int); 40 vector<int>G[maxn],W[maxn]; 41 int size[maxn]={0},son[maxn]={0}; 42 int depth[maxn]={0},p[maxn]={0},d[maxn][20],id[maxn][20]; 43 bool vis[maxn]={false},col[maxn]={false}; 44 int n,m,white,x,y,z; 45 char c; 46 int main(){ 47 freopen("QTREE4.in","r",stdin); 48 freopen("QTREE4.out","w",stdout); 49 scanf("%d",&n); 50 white=n; 51 for(int i=1;i<n;i++){ 52 scanf("%d%d%d",&x,&y,&z); 53 G[x].push_back(y); 54 W[x].push_back(z); 55 G[y].push_back(x); 56 W[y].push_back(z); 57 } 58 heap.push(0); 59 build(1,0,n,0); 60 scanf("%d",&m); 61 while(m--){ 62 scanf(" %c",&c); 63 if(c=='C'){ 64 scanf("%d",&x); 65 modify(x); 66 } 67 else{ 68 if(!white)printf("They have disappeared.\n"); 69 else if(white==1)printf("0\n"); 70 else printf("%d\n",heap.top()); 71 } 72 } 73 return 0; 74 } 75 void build(int x,int k,int s,int pr){ 76 int u=0; 77 dfs_getcenter(x,s,u); 78 vis[x=u]=true; 79 p[x]=pr; 80 depth[x]=k; 81 q[x].push(0); 82 if(s<=1)return; 83 for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]]){ 84 d[G[x][i]][k]=W[x][i]; 85 p[G[x][i]]=0; 86 dfs_getdis(G[x][i],G[x][i],k); 87 q[x].push(q1[G[x][i]][k].top()); 88 } 89 heap.push(q[x].top()+q[x].top2()); 90 for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]])build(G[x][i],k+1,size[G[x][i]],x); 91 } 92 void dfs_getcenter(int x,int s,int &u){ 93 size[x]=1; 94 son[x]=0; 95 for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]]&&G[x][i]!=p[x]){ 96 p[G[x][i]]=x; 97 dfs_getcenter(G[x][i],s,u); 98 size[x]+=size[G[x][i]]; 99 if(size[G[x][i]]>size[son[x]])son[x]=G[x][i]; 100 } 101 if(!u||max(s-size[x],size[son[x]])<max(s-size[u],size[son[u]]))u=x; 102 } 103 void dfs_getdis(int x,int v,int k){ 104 q1[v][k].push(d[x][k]); 105 size[x]=1;id[x][k]=v; 106 for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]]&&G[x][i]!=p[x]){ 107 p[G[x][i]]=x; 108 d[G[x][i]][k]=d[x][k]+W[x][i]; 109 dfs_getdis(G[x][i],v,k); 110 size[x]+=size[G[x][i]]; 111 } 112 } 113 void modify(int x){ 114 col[x]^=true; 115 if(col[x]){ 116 if(q[x].size()>1)heap.erase(q[x].top()+q[x].top2()); 117 q[x].erase(0); 118 if(q[x].size()>1)heap.push(q[x].top()+q[x].top2()); 119 white--; 120 } 121 else{ 122 if(q[x].size()>1)heap.erase(q[x].top()+q[x].top2()); 123 q[x].push(0); 124 if(q[x].size()>1)heap.push(q[x].top()+q[x].top2()); 125 white++; 126 } 127 for(int u=p[x],k=depth[x]-1;u;u=p[u],k--){ 128 if(col[x]){ 129 if(q[u].size()>1)heap.erase(q[u].top()+q[u].top2()); 130 q[u].erase(q1[id[x][k]][k].top()); 131 q1[id[x][k]][k].erase(d[x][k]); 132 if(!q1[id[x][k]][k].empty())q[u].push(q1[id[x][k]][k].top()); 133 if(q[u].size()>1)heap.push(q[u].top()+q[u].top2()); 134 } 135 else{ 136 if(q[u].size()>1)heap.erase(q[u].top()+q[u].top2()); 137 if(!q1[id[x][k]][k].empty())q[u].erase(q1[id[x][k]][k].top()); 138 q1[id[x][k]][k].push(d[x][k]); 139 q[u].push(q1[id[x][k]][k].top()); 140 if(q[u].size()>1)heap.push(q[u].top()+q[u].top2()); 141 } 142 } 143 } 144 /* 145 SPOJ2666 QTREE4 146 动态树分治,这次改用点分治。 147 每个重心的子树存一个堆维护到重心最远的白点,每个重心也存一个堆维护子树的答案, 148 重心的堆的前两大的元素就可以用来更新答案,把答案扔到一个全局堆里。 149 翻转时跳点分治树并修改对应子树和重心的堆,修改时顺便更新一下全局堆, 150 查询时O(1)取全局堆最大值即可。 151 */
没调出来的边分治……也贴过来好了……
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=400010; 8 struct edge{int to,w,prev;bool vis;edge():to(0),w(0),prev(0),vis(false){}}e[maxn<<1];//存新树的边,vis代表是否已被删除 9 struct A{//大根堆,维护答案 10 int x,d; 11 A(int x,int d):x(x),d(d){} 12 bool operator<(const A &a)const{return d<a.d;} 13 }; 14 void dfs_prework(int);//预处理,添虚点 15 void addedge(int,int,int);//在新树上添一条边 16 void build(int,int,int);//对以x为根的子树建边分治树 17 void dfs_getedge(int,int,int&);//找中心边 18 void dfs_getdis(int,int,int,int);//求距离 19 void modify(int);//翻转颜色 20 int getans(int);//更新点x对应的堆并返回当前答案 21 vector<int>G[maxn],W[maxn];//原树的边 22 int last[maxn],len=0,size[maxn]={0},p[maxn]={0};//建边分治树用的辅助数组 23 int eid[maxn],d[maxn][25],id[maxn][25],dir[maxn][25];//在深度为k的边分治树中的距离和左右,对应的点的编号 24 priority_queue<A>heap,q[maxn][2];//全局堆和边分治树的每个点的堆 25 int n,m,cnt,x,y,z,col[maxn]={0},white;//记一下每个点现在的颜色,0白1黑 26 char c; 27 int main(){ 28 freopen("QTREE4.in","r",stdin); 29 freopen("QTREE4.out","w",stdout); 30 memset(last,-1,sizeof(last)); 31 memset(eid,-1,sizeof(eid)); 32 scanf("%d",&n); 33 cnt=white=n; 34 for(int i=1;i<n;i++){ 35 scanf("%d%d%d",&x,&y,&z); 36 G[x].push_back(y); 37 W[x].push_back(z); 38 G[y].push_back(x); 39 W[y].push_back(z); 40 } 41 dfs_prework(1);//getchar();getchar(); 42 memset(p,0,sizeof(p));//printf("cnt=%d\n",cnt); 43 cnt=0; 44 build(1,0,n); 45 scanf("%d",&m); 46 while(m--){ 47 scanf(" %c",&c); 48 if(c=='C'){ 49 scanf("%d",&x); 50 modify(x); 51 } 52 else{ 53 while(!heap.empty()&&getans(heap.top().x)!=heap.top().d){ 54 //printf("heap.pop()=(%d,%d)\n",heap.top().x,heap.top().d); 55 x=heap.top().x; 56 heap.pop(); 57 if((z=getans(x))!=1<<31)heap.push(A(x,z)); 58 } 59 //printf("heap.size()=%d\n",heap.size()); 60 if(!white)printf("They have disappeared.\n"); 61 else if(white==1)printf("0\n"); 62 else printf("%d\n",max(heap.top().d,0)); 63 } 64 } 65 return 0; 66 } 67 void dfs_prework(int x){//预处理,添虚点 68 for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=p[x]){ 69 p[G[x][i]]=x; 70 dfs_prework(G[x][i]); 71 } 72 A y(0,0),z(0,0); 73 queue<A>q; 74 for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=p[x])q.push(A(G[x][i],W[x][i])); 75 while((int)q.size()>2){ 76 y=q.front();q.pop(); 77 z=q.front();q.pop(); 78 cnt++; 79 addedge(cnt,y.x,y.d); 80 addedge(y.x,cnt,y.d); 81 addedge(cnt,z.x,z.d); 82 addedge(z.x,cnt,z.d); 83 q.push(A(cnt,0)); 84 } 85 while(!q.empty()){ 86 y=q.front();q.pop(); 87 addedge(x,y.x,y.d); 88 addedge(y.x,x,y.d); 89 } 90 } 91 void addedge(int x,int y,int z){//在新树上添一条边 92 e[len].to=y;//printf("addedge(%d,%d,%d)\n",x,y,z); 93 e[len].w=z; 94 e[len].prev=last[x]; 95 last[x]=len++; 96 } 97 void build(int x,int k,int s){//对以x为根的子树建边分治树 98 if(s<=1)return; 99 int rt=++cnt;//printf("\n");printf("build(%d,%d,%d)\n",x,k,s); 100 dfs_getedge(x,s,eid[rt]); 101 int u=e[eid[rt]^1].to,v=e[eid[rt]].to;//printf("id=%d u=%d v=%d w=%d\n",eid[rt],u,v,e[eid[rt]].w); 102 e[eid[rt]].vis=e[eid[rt]^1].vis=true; 103 p[u]=p[v]=d[u][k]=d[v][k]=0; 104 dfs_getdis(u,rt,k,0); 105 dfs_getdis(v,rt,k,1); 106 if(!q[rt][0].empty()&&!q[rt][1].empty()){ 107 //printf("top=(%d,%d) w=%d\n",q[rt][0].top().d,q[rt][1].top().d,e[eid[rt]].w); 108 //printf("heap.push(%d,%d)\n",rt,q[rt][0].top().d+q[rt][1].top().d+e[eid[rt]].w); 109 heap.push(A(rt,q[rt][0].top().d+q[rt][1].top().d+e[eid[rt]].w)); 110 } 111 //else printf("EMPTY\n"); 112 build(u,k+1,s-size[v]); 113 build(v,k+1,size[v]); 114 } 115 void dfs_getedge(int x,int s,int &id){//找中心边 116 size[x]=1;//printf("dfs_getedge(%d,%d)\n",x,s); 117 for(int i=last[x];i!=-1;i=e[i].prev)if(!e[i].vis&&e[i].to!=p[x]){//printf("i=%d\n",i); 118 p[e[i].to]=x; 119 dfs_getedge(e[i].to,s,id); 120 size[x]+=size[e[i].to]; 121 if(id==-1||max(size[e[i].to],s-size[e[i].to])<max(size[e[id].to],s-size[e[id].to]))id=i; 122 } 123 } 124 void dfs_getdis(int x,int rt,int k,int c){//求距离,顺便完成对对应层id和dir的标号 125 //printf("dfs_getdis(%d,%d,%d,%d)\n",x,rt,k,c); 126 if(x<=n){ 127 //printf("q[%d][%d].push(%d,%d)\n",rt,c,x,d[x][k]); 128 q[rt][c].push(A(x,d[x][k])); 129 } 130 id[x][k]=rt;dir[x][k]=c; 131 for(int i=last[x];i!=-1;i=e[i].prev)if(!e[i].vis&&e[i].to!=p[x]){//printf("i=%d\n",i); 132 p[e[i].to]=x; 133 d[e[i].to][k]=d[x][k]+e[i].w; 134 dfs_getdis(e[i].to,rt,k,c); 135 } 136 } 137 void modify(int x){//翻转颜色 138 if(col[x])white++; 139 else white--; 140 col[x]^=1; 141 for(int i=20;i>=0;i--)if(id[x][i]){//如果是0表示深度过大不存在 142 getans(id[x][i]); 143 if(!col[x]){//原为黑色,入堆 144 if((q[id[x][i]][dir[x][i]].empty()||q[id[x][i]][dir[x][i]].top().d<d[x][i])&&!q[id[x][i]][dir[x][i]^1].empty()){ 145 heap.push(A(id[x][i],d[x][i]+q[id[x][i]][dir[x][i]^1].top().d+e[eid[id[x][i]]].w)); 146 //printf("heap.push(%d,%d)\n",id[x][i],d[x][i]+q[id[x][i]][dir[x][i]^1].top().d+e[eid[id[x][i]]].w); 147 } 148 //printf("q[%d][%d].push(%d,%d)\n",id[x][i],dir[x][i],x,d[x][i]); 149 q[id[x][i]][dir[x][i]].push(A(x,d[x][i])); 150 } 151 //否则原为白色,应当出堆,但我们只需等待这个堆被询问时再更新即可(懒惰更新) 152 } 153 } 154 int getans(int x){//更新点x对应的堆并返回当前答案 155 //printf("getans(%d)\n",x); 156 while(!q[x][0].empty()&&col[q[x][0].top().x])q[x][0].pop();//更新左边的堆 157 while(!q[x][1].empty()&&col[q[x][1].top().x])q[x][1].pop();//更新右边的堆 158 if(q[x][0].empty()||q[x][1].empty())return 1<<31;//如果左右有一个为空则说明有一半没有白点 159 else return q[x][0].top().d+q[x][1].top().d+e[eid[x]].w; 160 } 161 /* 162 5 163 1 2 1 164 2 3 1 165 2 4 -1 166 4 5 3 167 100000 168 A 169 C 5 170 A 171 C 3 172 A 173 C 5 174 A 175 C 5 176 A 177 C 5 178 A 179 C 5 180 A 181 C 2 182 A 183 C 1 184 A 185 C 4 186 A 187 C 2 188 A 189 C 4 190 A 191 C 3 192 A 193 C 2 194 A 195 */ 196 /* 197 SPOJ2666 QTREE4 198 基本思路就是边分治,每层中心边的两个端点存一个堆维护所代表子树中所有白点的距离, 199 再存一个全局堆维护边分治树的每个点所产生的答案。 200 翻转时在边分治树上修改logn个节点的堆即可,查询直接取全局堆的最大值,O(1)。 201 细节问题: 202 1.对每个点存它在深度为k的点分治树中到中心边的距离和属于中心边的哪一边,方便修改。 203 2.开一个数组记录每个点当前颜色,取最大值时方便查询最大值是否合法,不合法则pop掉重新取。 204 */
代码真的是错的……虽然把以1为根建树换成别的点就能过掉COGS上的数据,然而vjudge上怎么换都搞不过……
寒假准备好好搞搞动态树分治……让我挖个大坑……
233333333