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 */
View Code

没调出来的边分治……也贴过来好了……

  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 */
View Code

代码真的是错的……虽然把以1为根建树换成别的点就能过掉COGS上的数据,然而vjudge上怎么换都搞不过……

 

寒假准备好好搞搞动态树分治……让我挖个大坑……

bzoj4012 [HNOI2015]开店

bzoj3435 [Wc2014]紫荆花之恋

posted @ 2017-01-20 12:04  AntiLeaf  阅读(364)  评论(0编辑  收藏  举报