bzoj3052: [wc2013]糖果公园

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 using namespace std;
  7 #define maxn 100005
  8 typedef long long ll;
  9 ll ans,Ans[maxn];
 10 int n,m,q,temp,cnt1,deep[maxn],b[maxn],sum[maxn],block[maxn],Log[maxn],bz[maxn][21],a[maxn],dfn[maxn],tot,now[maxn],prep[maxn<<1],son[maxn<<1],wi[maxn],vi[maxn];
 11 bool can[maxn];
 12 struct Tsegment{
 13     int l,r,id;
 14 }qs[maxn];
 15 struct Fsegment{
 16     int u,v,bo,last;
 17 }ch[maxn];
 18 void read(int &x){
 19     x=0; int f=1; char Ch;
 20     for (Ch=getchar();Ch<'0'||Ch>'9';Ch=getchar()) if (Ch=='-') f=-1;
 21     for (;Ch>='0'&&Ch<='9';Ch=getchar()) x=x*10+Ch-'0'; x*=f;
 22 }
 23 bool comp(Tsegment x,Tsegment y){
 24     if (block[dfn[x.l]]!=block[dfn[y.l]]) return block[dfn[x.l]]<block[dfn[y.l]];
 25     if (block[dfn[x.r]]!=block[dfn[y.r]]) return block[dfn[x.r]]<block[dfn[y.r]];
 26     return x.id<y.id;
 27 }
 28 void add(int x,int y){
 29     prep[++tot]=now[x],now[x]=tot,son[tot]=y;
 30 }
 31 void dfs(int x,int fa){
 32     dfn[x]=++temp,bz[x][0]=fa,deep[x]=deep[fa]+1;
 33     for (int i=now[x],so=son[i];i;i=prep[i],so=son[i]){
 34         if (so==fa) continue;
 35         dfs(so,x);
 36     }
 37 }
 38 int Lca(int x,int y){
 39     if (x==y) return x;
 40     if (deep[x]<deep[y]) swap(x,y);
 41     while (deep[x]>deep[y]) x=bz[x][Log[deep[x]-deep[y]]];
 42     if (x==y) return x;
 43     while (bz[x][0]!=bz[y][0]){
 44         for (int i=20;i>=0;i--)
 45             if (bz[x][i]!=bz[y][i]){
 46                 x=bz[x][i],y=bz[y][i];
 47                 break;
 48             }
 49     }
 50     return bz[x][0];
 51 }
 52 void prepare(){
 53     temp=sqrt(n); 
 54     for (int i=1;i<=20;i++){
 55         for (int j=1;j<=n;j++){
 56             bz[j][i]=bz[bz[j][i-1]][i-1];
 57         }
 58     }
 59     for (int i=1;i<=n;i++) block[i]=(i-1)/temp+1;
 60 }
 61 void modify(int x){
 62     if (can[x]==0){
 63         can[x]=1;
 64         sum[a[x]]++;
 65         ans+=(1LL*wi[sum[a[x]]]*vi[a[x]]);
 66     }else{
 67         can[x]=0;
 68         ans-=(1LL*wi[sum[a[x]]]*vi[a[x]]);
 69         sum[a[x]]--;
 70     }
 71 }
 72 void change(int x,int y){
 73     for (;x!=y;){
 74         if (deep[x]<deep[y]) swap(x,y);
 75         modify(x); x=bz[x][0];
 76     }
 77 }
 78 void work(){
 79     memset(sum,0,sizeof(sum));
 80     memset(can,0,sizeof(can));
 81     temp=0,ans=qs[0].l=qs[0].r=0;
 82     for (int u,v,w,x,y,i=1;i<=cnt1;i++){
 83         u=qs[i].id;
 84         if (temp<=u){
 85             for (int j=temp;j<=u;j++){
 86                 if (ch[j].bo==0) continue;
 87                 x=ch[j].u,y=ch[j].v;
 88                 if (can[x]==1) modify(x),a[x]=y,modify(x);
 89                 else a[x]=y;
 90             }
 91         }else{
 92             for (int j=temp;j>=u;j--){
 93                 if (ch[j].bo==0) continue;
 94                 x=ch[j].u,y=ch[j].v;
 95                 if (can[x]==1) modify(x),a[x]=ch[j].last,modify(x);
 96                 else a[x]=ch[j].last;
 97             }
 98         } temp=u;
 99         int lca=Lca(qs[i].l,qs[i].r);
100         change(qs[i-1].l,qs[i].l);
101         change(qs[i-1].r,qs[i].r);
102         modify(lca);
103         Ans[qs[i].id]=ans;
104         modify(lca);
105     }
106 }
107 int main(){
108     read(n),read(m),read(q);
109     for (int i=1;i<=n;i++) Log[i]=log2(i);
110     for (int i=1;i<=m;i++) read(vi[i]);
111     for (int i=1;i<=n;i++) read(wi[i]);
112     tot=0,memset(now,0,sizeof(now));
113     for (int i=1,u,v;i<n;i++){
114         read(u),read(v);
115         add(u,v),add(v,u);
116     }
117     for (int i=1;i<=n;i++) read(a[i]);
118     memset(deep,0,sizeof(deep));
119     temp=cnt1=0,dfs(1,0);
120     prepare();
121     for (int i=1;i<=q;i++) ch[i].bo=0;
122     for (int type,x,y,i=1;i<=q;i++){
123         read(type),read(x),read(y);
124         if (type==1){
125             qs[++cnt1].id=i,qs[cnt1].l=x,qs[cnt1].r=y;
126             if (dfn[x]>dfn[y]) swap(qs[cnt1].l,qs[cnt1].r);
127         }else{
128             ch[i].u=x,ch[i].v=y,ch[i].bo=1;
129         }
130     }
131     sort(qs+1,qs+cnt1+1,comp);
132     for (int i=1;i<=n;i++) b[i]=a[i];
133     for (int i=1;i<=q;i++){
134         if (ch[i].bo==0) continue;
135         ch[i].last=b[ch[i].u],b[ch[i].u]=ch[i].v;
136     }
137     work();
138     for (int i=1;i<=q;i++){
139         if (ch[i].bo==1) continue;
140         printf("%lld
",Ans[i]);
141     }
142     return 0;
143 }
View Code

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3052

题目大意:

做法:带修改的树上莫队算法。

我们对所有询问排序,怎么排序呢?按左端点所在块为第一关键字,按右端点所在块为第二关键字,按操作的序号(以下称为时间)为第三关键字排序,然后依次暴力转移即可,每次转移时,先将时间暴力转移,即:若上次做完时间停在2,这次操作的时间戳为5,我们则需要把3~4的修改操作执行,暴力即可,如果上次为5,这次为2,则需要倒着还原修改操作。时间转移后利用对称差转移位置即可。及时更新答案即可,记得用1LL乘一下且用Long Long。

带修改的树上莫队算法。

原文地址:https://www.cnblogs.com/OYzx/p/5575539.html