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<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
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 <int>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.x<y.x||x.x==y.x&&belong[ld1[x.u]]<belong[ld1[y.u]]||x.x==y.x&&belong[ld1[x.u]]==belong[ld1[y.u]]&&belong[rd1[x.u]]<belong[rd1[y.u]];}
inline bool cmp2(quest x,quest y){return x.x>y.x||x.x==y.x&&belong[x.u]<belong[y.u]||x.x==y.x&&belong[x.u]==belong[y.u]&&belong[x.v]<belong[y.v];}
inline bool cmp3(quest x,quest y){return x.p<y.p;}
inline bool cmpx(num x,num y){return x.x<y.x;}
int w1[100001],w2[200002],fa[100001];
int tot,tot1,tot2;
inline void dfs(int d)
{
	tot1++;tot2++;
	w1[tot1]=d;w2[tot2]=d;
	ld1[d]=tot1;ld2[d]=tot2;
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(t!=fa[d])
		{
			fa[t]=d;
			dfs(t);
		}
	}
	rd1[d]=tot1;
	tot2++;
	w2[tot2]=d;
	rd2[d]=tot2;
}
inline long long gcd(long long x,long long y)
{
	if(y==0) return x;
	long long m=x%y;
	while(m!=0)
	{
		x=y;
		y=m;
		m=x%y;
	}
	return y;
}
long long ss[100001],sx[100001];
inline void change1(int x)
{
	if(!v[w1[x]])
	{
		v[w1[x]]=true;
		sx[ss[fx[w1[x]]]++]-=val[w1[x]];
//		ss[fx[w1[x]]]++;
		sx[ss[fx[w1[x]]]]+=val[w1[x]];
	}
	else
	{
		v[w1[x]]=false;
		sx[ss[fx[w1[x]]]--]-=val[w1[x]];
//		ss[fx[w1[x]]]--;
		sx[ss[fx[w1[x]]]]+=val[w1[x]];
	}
}
inline void change2(int x)
{
	if(!v[w2[x]])
	{
		v[w2[x]]=true;
		sx[ss[fx[w2[x]]]++]-=val[w2[x]];
	//	ss[fx[w2[x]]]++;
		sx[ss[fx[w2[x]]]]+=val[w2[x]];
	}
	else
	{
		v[w2[x]]=false;
		sx[ss[fx[w2[x]]]--]-=val[w2[x]];
	//	ss[fx[w2[x]]]--;
		sx[ss[fx[w2[x]]]]+=val[w2[x]];
	}
}
inline void reverse(int x)
{
	if(!v[x])
	{
		v[x]=true;
		sx[ss[fx[x]]++]-=val[x];
//		ss[fx[x]]++;
		sx[ss[fx[x]]]+=val[x];
	}
	else
	{
		v[x]=false;
		sx[ss[fx[x]]--]-=val[x];
//		ss[fx[x]]--;
		sx[ss[fx[x]]]+=val[x];
	}
}
int main()
{
	freopen("1007.in","r",stdin);
	freopen("1007.out","w",stdout);
	int k=0,T;
//	scanf("%d",&T);
	T=read();
	while(T>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(r<rd1[ask[i].u]){r++;change1(r);}
			while(r>rd1[ask[i].u]){change1(r);r--;}
			while(l<ld1[ask[i].u]){change1(l);l++;}
			while(l>ld1[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(r<ask[i].v){r++;change2(r);}
			while(r>ask[i].v){change2(r);r--;}
			while(l<ask[i].u){change2(l);l++;}
			while(l>ask[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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值