【点分治】hdu4670

好久没写树分治了,稍微复习一下,顺便吐一吐槽。。。

最近一场warming两场网络赛,前两次还好,最后一次真是跌出历史最低水平了,整个队伍处于一种奇怪的状态,然后最近又在牙疼,貌似是长智齿,各种混乱。。。

这道题是询问树上有多少条路径的点权积是三次方数,直接点分治求过每个点的方案,每次用map暴力统计一下,一开始re是一直用dfs写树分治爆栈了,以后能bfs还是尽量bfs吧。。。后来tle,是我脑残用string存在map里面,明明是可以压位的,string的唯一好处是好输出调试。。。后来wa是win8用lld读入longlong,结果我定义的int,用I64d不报错,真心坑。。。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <utility>
const int oo=1073741819;
using namespace std;
int tail[200000],next[2000000],sora[2000000];
int a[60000][31],st[60000],v[60000],size[60000],rt[60000],rel[60000],bj[60000];
int pri[60000][31],ans;
long long d[36],b[60000],p[31],w[60000];
int ts[60000];
int c[31],sign;
map < long long , int > hash;
int n,ss,rr,w_time,k,max_size,root;
void bfs(int s) 
{
	int h,r,ne,na;
	h=r=0;
	st[r=1]=s,v[s]=w_time;
	for (;h<r;) {
		ne=st[++h],size[ne]=0;
		for (int i=ne;next[i];) {
			i=next[i],na=sora[i];
			if (!rel[na] && v[na]!=w_time) {
				v[na]=w_time,rt[na]=ne;
				st[++r]=na;
			}
		}
	}
	for (int i=r;i>=1;i--) {
		ne=st[i];
		size[ne]++;
		//cout<<ne<<' '<<size[ne]<<endl;
		size[rt[ne]]+=size[ne];
		int tmp=r-size[ne];
		for (int i=ne;next[i];) {
			i=next[i],na=sora[i];
			if (v[na]==w_time && na!=rt[ne]) tmp=max(tmp,size[na]);
		}
		if (tmp<max_size) max_size=tmp,root=ne;
		//cout<<ne<<' '<<tmp<<endl;
	}
}
void bfs2(int s)
{
	int h,r,ne,na;
	h=r=0;
	st[r=1]=s,v[s]=w_time,bj[s]=sign;
	for (;h<r;) {
		ne=st[++h],ts[++rr]=ne;
		hash[b[ne]]++;
		for (int i=ne;next[i];) {
			i=next[i],na=sora[i];
			if (!rel[na] && v[na]!=w_time) {
				v[na]=w_time,bj[na]=sign;
				st[++r]=na;
				b[na]=0;
				for (int i=1;i<=k;i++) a[na][i]=(a[ne][i]+pri[na][i])%3,b[na]=b[na]+d[i]*a[na][i];
			}
		}
	}
} 
long long doit(int c[31],int e[31])
{
	long long tmp=0;
	tmp=0;
	for (int i=1;i<=k;i++) tmp=tmp+d[i]*(((3-c[i]+e[i])%3));
	return tmp;
}
void mysoul(int s)
{
//	cout<<' '<<s<<endl;
    max_size=oo,root=0;
    w_time++;
    bfs(s);
    s=root,rel[s]=1;
// cout<<max_size<<endl;
    for (int i=1;i<=k;i++) a[s][i]=pri[s][i]%3;
    rr=0,hash.clear();
    for (int i=s,ne;next[i];) {
        i=next[i],ne=sora[i];
        if (!rel[ne]) {
            ++w_time,sign=ne;
            b[ne]=0;
            for (int i=1;i<=k;i++) a[ne][i]=(a[s][i]+pri[ne][i])%3,b[ne]+=d[i]*a[ne][i];
            //cout<<1<<endl;
            bfs2(ne);
        }
    }
    //cout<<' '<<s<<endl;
    long long tmp=doit(a[s],a[s]);
    ans+=hash[tmp]*2;
//    cout<<tmp<<' '<<ans<<' '<<bj[5]<<' '<<bj[4]<<endl;
    //for (int i=1;i<=rr;i++) cout<<b[ts[i]]<<' ';cout<<endl;
    for (int i=1,op,ed;i<=rr;i=ed+1) {
    	op=i;
    	//cout<<hash[6]<<endl;
    	for (ed=op;bj[ts[ed]]==bj[ts[op]] && ed<=rr;ed++) hash[b[ts[ed]]]--;
    	ed--;
//    	cout<<op<<' '<<ed<<endl;
    	for (int j=op;j<=ed;j++) {
    		tmp=doit(a[ts[j]],a[s]);
				ans+=hash[tmp];
//				cout<<ts[j]<<' '<<tmp<<' '<<b[ts[j]]<<' '<<ans<<endl;
    	}
    	for (int j=op;j<=ed;j++) hash[b[ts[j]]]++;
    }
//    cout<<s<<' '<<ans<<endl;
    for (int i=s,ne;next[i];) {
    	i=next[i],ne=sora[i];
    	if (!rel[ne]) mysoul(ne);
    }
}
void origin()
{
	ss=n;
	for (int i=1;i<=n;i++) tail[i]=i,next[i]=0;
}
void link(int x,int y)
{
	++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0;
	++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0;
}
int main()
{
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
    for (;cin>>n;) {
        scanf("%d",&k);
        origin();
        for (int i=1;i<=k;i++) scanf("%lld",&p[i]);
        d[0]=1;
        for (int i=1;i<=k;i++) d[i]=d[i-1]*3;
        for (int i=1;i<=n;i++) scanf("%lld",&w[i]);
        for (int i=1;i<=n;i++) {
            long long tmp=w[i];            
            for (int j=1;j<=k;j++) {
                pri[i][j]=0;
                for (;tmp && tmp%p[j]==0;tmp/=p[j]) pri[i][j]++;
            }
        }
        for (int i=1;i<=n-1;i++) {
        	int x,y;
            scanf("%d%d",&x,&y);
            link(x,y);
        }
        for (int i=1;i<=n;i++) rel[i]=0;
        for (int i=1;i<=n;i++) v[i]=0;
        w_time=0;
        ans=0;
        mysoul(1);
        for (int i=1;i<=n;i++) {
        	int tmp=0;
        	for (int j=1;j<=k;j++) tmp+=pri[i][j]%3;
        	ans+=(tmp==0)*2;
        }
        cout<<ans/2<<endl;
    }
    return 0;
}


你可能感兴趣的:(【点分治】hdu4670)