2016多校训练Contest6: 1007 This world need more Zhu hdu5799

Problem Description
As we all know,Zhu is the most powerful man.He has the infinite power to protest the world.We need more men like Zhu!

In Duoladuo,this place is like a tree.There are n points and n-1 edges.And the root is 1.Each point can reach other points.Each point has a value a[i] named Zhu power.

Liao is a curious baby,he has m questions to ask Zhu.But now Zhu is busy,he wants you to help him answer Liao's questions.

Liao's question will be like"op u v a b".

if op is "1",the u is equal to v.Liao wants to know the GCD of the sum of numbers thats appears a times and the sum of numbers that appears b times in subtree u.

if op is "2",Liao wants to know the GCD of the sum of numbers thats appears a times and the sum of numbers that appears b times on the path from u to v.

GCD is greatest common divisor.

notice:we can know GCD(x,0) = x.
 

Input
In the first line contains a single positive integer T, indicating number of test case.

In the second line there are two numbers n,m.n is the size of Duoladuo.m is the number of Liao's questions.

The next line contains n integers A1, A2, ...AN, means the value of i point.

In the next n-1 line contains tow numbers u,v.It means there is a edge between point u and point v.


The next m lines will be the Liao's question: 

1 u v a b.

2 u v a b.

1T10,1n100000,1m100000,1op2,1u,vn,1a,bn,1A[i]1000000000.
 

Output
For each case, output Case #i:. (ii is the number of the test case, from 1 to T). 

Then, you need to output the answer for every Liao's questions.
 

Sample Input
 
   
1 5 5 1 2 4 1 2 1 2 2 3 3 4 4 5 1 1 1 1 1 1 1 1 1 2 2 1 5 1 1 2 1 5 1 2 2 1 1 2 2
 

Sample Output
 
   
Case #1: 4 1 4 1 0
Hint
The query1: gcd(4,4) = 4 The query2: gcd(4,1+2)=1 The query3: gcd(4,4) = 4 The query4: gcd(4,1+2) = 1 The query5: gcd(0,0) = 0


先抱怨几句。

总之到现在这题我还在被卡常数。似乎出题人并没有打算放按照dfs序做树分块的人过【不过也有过的,然后出题人收获fread优化模版一份】

不明白卡这个有什么意义...因为题目本身难度不大就在这方面来卡做题的人么

理论复杂度分析:O(10*10w*sqrt(10w))≈O(3.1E)

时间限制:5S

顺便STD跑了3.1S

-----------------------------------------------------------------------------------------------------------------------------------------

这题的做法是树上莫队

对于第一种询问,我们可以直接按照dfs序列分块

对于第二种询问,我们有两种分块方法。

一是树分块,二是dfs序分块

dfs序分块较为稳定,但是因为每个点要存储两遍所以自带了两倍常数

如果数据稍微倾向树分块的话,出题人便可以这种做法卡掉

STD树上分块是3.1S,第二种分块方法多一倍常数的话直接就过不去了

因为我的树分块一直写的不怎么样所以并不是太想重新写一遍。。

就把现在的程序贴出来吧。

本机大概10S左右。有时间再改改。。

大概还有我的莫队多跑一遍的原因也使得常数增加了

#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline long long read()
{
    long long 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;
}
struct line
{
	int s,t;
	int next;
}a[200001];
int head[100001],edge;
inline void add(int s,int t)
{
	a[edge].next=head[s];
	head[s]=edge;
	a[edge].s=s;
	a[edge].t=t;
}
bool v[200001];
int deep[100001];
int ans[100001][17];
inline void bfs(int r)
{
     int i,j;
     deep[r]=1;
     for(i=0;i<=16;i++) ans[r][i]=r;
     queue Q;
     while(!Q.empty()) Q.pop();
     Q.push(r); v[r]=true;
     while(!Q.empty())
     {
          int d=Q.front(); Q.pop();
          for(i=head[d];i!=0;i=a[i].next)
          {
               int t=a[i].t;
               if(!v[t])
               {
                    v[t]=true; Q.push(t);
                    deep[t]=deep[d]+1;
                    ans[t][0]=d;
                    for(j=1;j<=16;j++){int dt=ans[t][j-1];ans[t][j]=ans[dt][j-1];}
               }
          }
     }
}
inline int swim(int x,int y)
{
	 int i=16;
     while(deep[x]!=deep[y])
     {
          while(deep[ans[y][i]]<=deep[x]&&i>0) i--;
          y=ans[y][i];
          if(i>0) i--;
     }
     return y;
}
inline int lca(int x,int y)
{
     if(deep[x]>deep[y]){int t=x; x=y; y=t;}
     y=swim(x,y);
     int i=16;
     while(x!=y)
     {
          while(ans[x][i]==ans[y][i]&&i>0) i--;
          x=ans[x][i]; y=ans[y][i];
          if(i>0) i--;
     }
     return x;
}
//----------------------------------------------------------------------------------------------------------
struct quest
{
	int x,u,v,a,b,p;
	long long ans;
}ask[100001];
struct num
{
	int x,p;
	long long ans;
}f[100001];
int fx[100001],belong[200001],ld1[100001],rd1[100001],ld2[100001],rd2[100001];
long long val[100001];
inline bool cmp1(quest x,quest y){return x.xy.x||x.x==y.x&&belong[x.u]0)
	{
		k++;T--;
		memset(head,0,sizeof(head));
		memset(fa,0,sizeof(fa));
		memset(a,0,sizeof(a));
		edge=tot1=tot2=tot=0;
		int n,m;
		n=read();m=read();
		//scanf("%d%d",&n,&m);
		int i,s,t;
		for(i=1;i<=n;i++)
		{
			val[i]=read();
			//scanf("%I64d",&val[i]);
			f[i].x=val[i];f[i].p=i;
		}
		sort(f+1,f+1+n,cmpx);
		tot++;fx[f[1].p]=tot;
		for(i=2;i<=n;i++)
		{
			if(f[i].x!=f[i-1].x) tot++;
			fx[f[i].p]=tot;
		}
		for(i=1;i<=n-1;i++)
		{
			s=read();t=read();
			//scanf("%d%d",&s,&t);
			edge++; add(s,t);
			edge++; add(t,s);
		}
		dfs(1);
		memset(v,false,sizeof(v));
		bfs(1);
		for(i=1;i<=m;i++)
		{
		//	scanf("%d%d%d%d%d",&ask[i].x,&ask[i].u,&ask[i].v,&ask[i].a,&ask[i].b);
			ask[i].x=read();ask[i].u=read();ask[i].v=read();ask[i].a=read();ask[i].b=read();
			if(ld1[ask[i].u]>ld1[ask[i].v]) swap(ask[i].u,ask[i].v);
			ask[i].p=i;
		}
		int nt=sqrt(tot1)/3*13;
		for(i=1;i<=tot1;i++) belong[i]=(i-1)/nt+1;
		sort(ask+1,ask+1+m,cmp1);
		int l=1,r=0;
		memset(v,false,sizeof(v));
		memset(sx,0,sizeof(sx));
		memset(ss,0,sizeof(ss));
		for(i=1;i<=m;i++)
		{
			if(ask[i].x!=1) break;
			while(rrd1[ask[i].u]){change1(r);r--;}
			while(lld1[ask[i].u]){l--;change1(l);}
			ask[i].ans=gcd(sx[ask[i].a],sx[ask[i].b]);
		}
		int tt=i;
		nt=sqrt(tot2)/3*7;
		for(i=1;i<=tot2;i++) belong[i]=(i-1)/nt+1;
		memset(v,false,sizeof(v));
		for(i=tt;i<=m;i++)
		{
			ask[i].u=rd2[ask[i].u];
			ask[i].v=ld2[ask[i].v];
			if(ask[i].u>ask[i].v)
				ask[i].u=ld2[w2[ask[i].u]];
		}
		sort(ask+tt,ask+1+m,cmp2);
		memset(v,false,sizeof(v));
		memset(sx,0,sizeof(sx));
		memset(ss,0,sizeof(ss));
		l=1;r=0;
		bool flag=false;
		for(i=tt;i<=m;i++)
		{
			if(ask[i].x!=2) break;
			while(rask[i].v){change2(r);r--;}
			while(lask[i].u){l--;change2(l);}
			int t=lca(w2[l],w2[r]);
			if(w2[ask[i].u]!=t&&w2[ask[i].v]!=t){reverse(t);flag=true;}
			ask[i].ans=gcd(sx[ask[i].a],sx[ask[i].b]);
			if(flag){reverse(t);flag=false;}
		}
		sort(ask+1,ask+1+m,cmp3);
		printf("Case #%d:\n",k);
		for(i=1;i<=m;i++)
			printf("%I64d\n",ask[i].ans);
	}
	return 0;
}


你可能感兴趣的:(莫队算法,分块)