BZOJ3757: 苹果树

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3757

题解:

颜色种数不太好用树形数据结构维护,因为子节点的信息不能快速合并为父节点的信息。而莫队算法正是解决这类题目的利器。

节点与节点间的转移可以戳vfleaking的blog:http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

比较巧妙的一点是把麻烦的lca去掉,然后统计答案的时候加上,统计完了再删去。

其实我做这题是为了测试各种树分块的快慢。。。

#1 按王室联邦的分块方法,可以保证所有的块内距离<=sqrt(n),最多有一块的大小>sqrt(n)并且<3sqrt(n)。块内可能是不连通的。

    但这对我们算法的执行并没有什么影响,因为它只是作为莫队算法排序的参照(可以说是估价函数)。

    块大小sqrt(n) 耗时 8744ms

    块大小sqrt(n*log2(n)) 耗时 7520ms

技术分享
  1 #include<cstdio>
  2 
  3 #include<cstdlib>
  4 
  5 #include<cmath>
  6 
  7 #include<cstring>
  8 
  9 #include<algorithm>
 10 
 11 #include<iostream>
 12 
 13 #include<vector>
 14 
 15 #include<map>
 16 
 17 #include<set>
 18 
 19 #include<queue>
 20 
 21 #include<string>
 22 
 23 #define inf 1000000000
 24 
 25 #define maxn 200000+5
 26 
 27 #define maxm 200000+5
 28 
 29 #define eps 1e-10
 30 
 31 #define ll long long
 32 
 33 #define pa pair<int,int>
 34 
 35 #define for0(i,n) for(int i=0;i<=(n);i++)
 36 
 37 #define for1(i,n) for(int i=1;i<=(n);i++)
 38 
 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 40 
 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 42 
 43 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 44 
 45 #define for5(n,m) for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
 46 
 47 #define mod 1000000007
 48 
 49 using namespace std;
 50 
 51 inline int read()
 52 
 53 {
 54 
 55     int x=0,f=1;char ch=getchar();
 56 
 57     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
 58 
 59     while(ch>=0&&ch<=9){x=10*x+ch-0;ch=getchar();}
 60 
 61     return x*f;
 62 
 63 }
 64 int n,m,size,top,cnt,tot,rt,ti,ret;
 65 int a[maxn],head[maxn],ans[maxn],s[maxn],b[maxn],pos[maxn],sta[maxn],f[maxn][18],dep[maxn];
 66 struct rec{int l,r,x,y,id;}q[maxn];
 67 struct edge{int go,next;}e[2*maxn];
 68 bool v[maxn];
 69 inline void add(int x,int y)
 70 {
 71     e[++tot]=(edge){y,head[x]};head[x]=tot;
 72     e[++tot]=(edge){x,head[y]};head[y]=tot;
 73 }
 74 inline void dfs(int x)
 75 {
 76     pos[x]=++ti;int tmp=top;
 77     for1(i,17)if(dep[x]>=1<<i)f[x][i]=f[f[x][i-1]][i-1];else break;
 78     for4(i,x)if(y!=f[x][0])
 79     {
 80         f[y][0]=x;dep[y]=dep[x]+1;
 81         dfs(y);
 82         if(top-tmp>=size)
 83         {
 84             ++cnt;
 85             while(top!=tmp)b[sta[top--]]=cnt;
 86         }
 87     }
 88     sta[++top]=x;
 89 }
 90 inline int lca(int x,int y)
 91 {
 92     if(dep[x]<dep[y])swap(x,y);
 93     int t=dep[x]-dep[y];
 94     for0(i,17)if(t&(1<<i))x=f[x][i];
 95     if(x==y)return x;
 96     for3(i,17,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
 97     return f[x][0];
 98 }
 99 inline void change(int x)
100 {
101     if(v[x]){s[a[x]]--;if(!s[a[x]])ret--;}
102     else {s[a[x]]++;if(s[a[x]]==1)ret++;}
103     v[x]^=1;
104 }
105 inline void work(int x,int y)
106 {
107     while(x!=y)
108     {
109         if(dep[x]<dep[y])swap(x,y);
110         change(x);
111         x=f[x][0];
112     }
113 }
114 inline bool cmp(rec x,rec y){return b[x.l]==b[y.l]?pos[x.r]<pos[y.r]:b[x.l]<b[y.l];}
115 
116 int main()
117 
118 {
119 
120     freopen("input.txt","r",stdin);
121 
122     freopen("output.txt","w",stdout);  
123     n=read();m=read();
124     for1(i,n)a[i]=read();
125     for1(i,n){int x=read(),y=read();add(x,y);if(x*y==0)rt=x+y;}
126     size=sqrt(n);
127     dfs(rt);
128     while(top)b[sta[top--]]=cnt;
129     for1(i,m)
130     {
131         q[i].l=read(),q[i].r=read(),q[i].x=read(),q[i].y=read(),q[i].id=i;
132         if(b[q[i].l]>b[q[i].r])swap(q[i].l,q[i].r);
133     }
134     sort(q+1,q+m+1,cmp);
135     int l=rt,r=rt;
136     for1(i,m)
137     {
138         work(l,q[i].l);work(r,q[i].r);
139         l=q[i].l;r=q[i].r;int f=lca(l,r);
140         change(f);
141         ans[q[i].id]=ret-(int)(q[i].x!=q[i].y&&s[q[i].x]&&s[q[i].y]);
142         change(f);
143     }
144     for1(i,m)printf("%d\n",ans[i]);
145 
146     return 0;
147 
148 }  
View Code

 

#2 按照块状树的分块方法,如果一个节点父节点所在块的大小还没有达到sqrt(n),就把该点塞入父亲所在块,否则另开一块。

     这样可以保证块内的所有点都是连通的。但是由于是从上到下分,所以会被菊花图卡到块数为O(n)

     块大小sqrt(n) 耗时 9448ms

     块大小sqrt(n*log2(n)) 耗时 7180ms

技术分享
  1 #include<cstdio>
  2 
  3 #include<cstdlib>
  4 
  5 #include<cmath>
  6 
  7 #include<cstring>
  8 
  9 #include<algorithm>
 10 
 11 #include<iostream>
 12 
 13 #include<vector>
 14 
 15 #include<map>
 16 
 17 #include<set>
 18 
 19 #include<queue>
 20 
 21 #include<string>
 22 
 23 #define inf 1000000000
 24 
 25 #define maxn 200000+5
 26 
 27 #define maxm 200000+5
 28 
 29 #define eps 1e-10
 30 
 31 #define ll long long
 32 
 33 #define pa pair<int,int>
 34 
 35 #define for0(i,n) for(int i=0;i<=(n);i++)
 36 
 37 #define for1(i,n) for(int i=1;i<=(n);i++)
 38 
 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 40 
 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 42 
 43 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 44 
 45 #define for5(n,m) for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
 46 
 47 #define mod 1000000007
 48 
 49 using namespace std;
 50 
 51 inline int read()
 52 
 53 {
 54 
 55     int x=0,f=1;char ch=getchar();
 56 
 57     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
 58 
 59     while(ch>=0&&ch<=9){x=10*x+ch-0;ch=getchar();}
 60 
 61     return x*f;
 62 
 63 }
 64 int n,m,size,top,cnt,tot,rt,ti,ret;
 65 int a[maxn],head[maxn],sum[maxn],ans[maxn],s[maxn],b[maxn],pos[maxn],sta[maxn],f[maxn][18],dep[maxn];
 66 struct rec{int l,r,x,y,id;}q[maxn];
 67 struct edge{int go,next;}e[2*maxn];
 68 bool v[maxn];
 69 inline void add(int x,int y)
 70 {
 71     e[++tot]=(edge){y,head[x]};head[x]=tot;
 72     e[++tot]=(edge){x,head[y]};head[y]=tot;
 73 }
 74 inline void dfs(int x)
 75 {
 76     pos[x]=++ti;
 77     for1(i,17)if(dep[x]>=1<<i)f[x][i]=f[f[x][i-1]][i-1];else break;
 78     for4(i,x)if(y!=f[x][0])
 79     {
 80         f[y][0]=x;dep[y]=dep[x]+1;
 81         sum[b[y]=sum[b[x]]<size?b[x]:++cnt]++;
 82         dfs(y);
 83     }
 84 }
 85 inline int lca(int x,int y)
 86 {
 87     if(dep[x]<dep[y])swap(x,y);
 88     int t=dep[x]-dep[y];
 89     for0(i,17)if(t&(1<<i))x=f[x][i];
 90     if(x==y)return x;
 91     for3(i,17,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
 92     return f[x][0];
 93 }
 94 inline void change(int x)
 95 {
 96     if(v[x]){s[a[x]]--;if(!s[a[x]])ret--;}
 97     else {s[a[x]]++;if(s[a[x]]==1)ret++;}
 98     v[x]^=1;
 99 }
100 inline void work(int x,int y)
101 {
102     while(x!=y)
103     {
104         if(dep[x]<dep[y])swap(x,y);
105         change(x);
106         x=f[x][0];
107     }
108 }
109 inline bool cmp(rec x,rec y){return b[x.l]==b[y.l]?pos[x.r]<pos[y.r]:b[x.l]<b[y.l];}
110 
111 int main()
112 
113 {
114 
115     freopen("input.txt","r",stdin);
116 
117     freopen("output.txt","w",stdout);  
118     n=read();m=read();
119     for1(i,n)a[i]=read();
120     for1(i,n){int x=read(),y=read();add(x,y);if(x*y==0)rt=x+y;}
121     size=sqrt(n);
122     sum[1]=b[1]=cnt=1;
123     dfs(rt);
124     for1(i,m)
125     {
126         q[i].l=read(),q[i].r=read(),q[i].x=read(),q[i].y=read(),q[i].id=i;
127         if(b[q[i].l]>b[q[i].r])swap(q[i].l,q[i].r);
128     }
129     sort(q+1,q+m+1,cmp);
130     int l=rt,r=rt;
131     for1(i,m)
132     {
133         work(l,q[i].l);work(r,q[i].r);
134         l=q[i].l;r=q[i].r;int f=lca(l,r);
135         change(f);
136         ans[q[i].id]=ret-(int)(q[i].x!=q[i].y&&s[q[i].x]&&s[q[i].y]);
137         change(f);
138     }
139     for1(i,m)printf("%d\n",ans[i]);
140 
141     return 0;
142 
143 }  
View Code

#3 直接把dfs序拉出来,做序列上的分块。这样有可能块内两点之间离了很远。感觉效果不会很好,但是好写。。。

    耗时 16800ms

技术分享
  1 #include<cstdio>
  2 
  3 #include<cstdlib>
  4 
  5 #include<cmath>
  6 
  7 #include<cstring>
  8 
  9 #include<algorithm>
 10 
 11 #include<iostream>
 12 
 13 #include<vector>
 14 
 15 #include<map>
 16 
 17 #include<set>
 18 
 19 #include<queue>
 20 
 21 #include<string>
 22 
 23 #define inf 1000000000
 24 
 25 #define maxn 200000+5
 26 
 27 #define maxm 200000+5
 28 
 29 #define eps 1e-10
 30 
 31 #define ll long long
 32 
 33 #define pa pair<int,int>
 34 
 35 #define for0(i,n) for(int i=0;i<=(n);i++)
 36 
 37 #define for1(i,n) for(int i=1;i<=(n);i++)
 38 
 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 40 
 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 42 
 43 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 44 
 45 #define for5(n,m) for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
 46 
 47 #define mod 1000000007
 48 
 49 using namespace std;
 50 
 51 inline int read()
 52 
 53 {
 54 
 55     int x=0,f=1;char ch=getchar();
 56 
 57     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
 58 
 59     while(ch>=0&&ch<=9){x=10*x+ch-0;ch=getchar();}
 60 
 61     return x*f;
 62 
 63 }
 64 int n,m,size,top,cnt,tot,rt,ti,ret;
 65 int a[maxn],head[maxn],sum[maxn],ans[maxn],s[maxn],b[maxn],pos[maxn],sta[maxn],f[maxn][18],dep[maxn];
 66 struct rec{int l,r,x,y,id;}q[maxn];
 67 struct edge{int go,next;}e[2*maxn];
 68 bool v[maxn];
 69 inline void add(int x,int y)
 70 {
 71     e[++tot]=(edge){y,head[x]};head[x]=tot;
 72     e[++tot]=(edge){x,head[y]};head[y]=tot;
 73 }
 74 inline void dfs(int x)
 75 {
 76     pos[x]=++ti;
 77     for1(i,17)if(dep[x]>=1<<i)f[x][i]=f[f[x][i-1]][i-1];else break;
 78     for4(i,x)if(y!=f[x][0])
 79     {
 80         f[y][0]=x;dep[y]=dep[x]+1;
 81         dfs(y);
 82     }
 83 }
 84 inline int lca(int x,int y)
 85 {
 86     if(dep[x]<dep[y])swap(x,y);
 87     int t=dep[x]-dep[y];
 88     for0(i,17)if(t&(1<<i))x=f[x][i];
 89     if(x==y)return x;
 90     for3(i,17,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
 91     return f[x][0];
 92 }
 93 inline void change(int x)
 94 {
 95     if(v[x]){s[a[x]]--;if(!s[a[x]])ret--;}
 96     else {s[a[x]]++;if(s[a[x]]==1)ret++;}
 97     v[x]^=1;
 98 }
 99 inline void work(int x,int y)
100 {
101     while(x!=y)
102     {
103         if(dep[x]<dep[y])swap(x,y);
104         change(x);
105         x=f[x][0];
106     }
107 }
108 inline bool cmp(rec x,rec y){return b[pos[x.l]]==b[pos[y.l]]?pos[x.r]<pos[y.r]:b[pos[x.l]]<b[pos[y.l]];}
109 
110 int main()
111 
112 {
113 
114     freopen("input.txt","r",stdin);
115 
116     freopen("output.txt","w",stdout);  
117     n=read();m=read();
118     for1(i,n)a[i]=read();
119     for1(i,n){int x=read(),y=read();add(x,y);if(x*y==0)rt=x+y;}
120     size=sqrt(n);
121     dfs(rt);
122     for1(i,n)b[i]=(i-1)/size+1;
123     for1(i,m)
124     {
125         q[i].l=read(),q[i].r=read(),q[i].x=read(),q[i].y=read(),q[i].id=i;
126         if(b[q[i].l]>b[q[i].r])swap(q[i].l,q[i].r);
127     }
128     sort(q+1,q+m+1,cmp);
129     int l=rt,r=rt;
130     for1(i,m)
131     {
132         work(l,q[i].l);work(r,q[i].r);
133         l=q[i].l;r=q[i].r;int f=lca(l,r);
134         change(f);
135         ans[q[i].id]=ret-(int)(q[i].x!=q[i].y&&s[q[i].x]&&s[q[i].y]);
136         change(f);
137     }
138     for1(i,m)printf("%d\n",ans[i]);
139 
140     return 0;
141 
142 }  
View Code

按dfs序分块果然是做死。。。七爷有更好的办法?

从此AC率是路人T_T

 

   

  

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。