点分治

这怕是noip的考试范围哦。Achen在半年前就会了的算法我现在都不会。


自己比较智障,连写3道题都是get_root()之后就去solve(z)而不是solve(root),搞得又T又RE

点分治模板(洛谷)

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<set>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=1e4+7;
int n,m,ans[maxn],p[maxn];
int size[maxn],son[maxn],sumsize,root,vis[maxn],len[maxn];

char cc; ll ff;
template<typename T>void read(T& aa) {
    aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}
int fir[maxn],nxt[2*maxn],to[2*maxn],v[2*maxn],e=0;
void add(int x,int y,int z) {
    to[++e]=y;nxt[e]=fir[x];fir[x]=e;v[e]=z;
    to[++e]=x;nxt[e]=fir[y];fir[y]=e;v[e]=z;
}

void get_root(int pos,int f) {
    size[pos]=1; son[pos]=0; int y,z;
    for(y=fir[pos];y;y=nxt[y]) {
        if((z=to[y])==f||vis[z]) continue;
        get_root(z,pos);
        size[pos]+=size[z];
        son[pos]=max(son[pos],size[z]);
    }
    son[pos]=max(son[pos],sumsize-size[pos]);
    if(son[pos]<son[root]) root=pos;
}

set<int> G;
int zz[maxn],t;
void get_ans(int x) {
    For(i,1,m) if(G.find(p[i]-x)!=G.end()) ans[i]|=1;
}

void dfs(int pos,int f) {
    int y,z; zz[++t]=len[pos];
    get_ans(len[pos]);
    for(y=fir[pos];y;y=nxt[y]) {
        if(vis[z=to[y]]||z==f) continue;
        len[z]=len[pos]+v[y]; dfs(z,pos);
    }
}

void solve(int pos) {
    vis[pos]=1; G.clear(); G.insert(0);
    int y,z;
    for(y=fir[pos];y;y=nxt[y]) {
        if(vis[z=to[y]]) continue;
        len[z]=v[y]; dfs(z,pos);
        while(t) G.insert(zz[t--]);
    }
    for(y=fir[pos];y;y=nxt[y]) {
        if(vis[z=to[y]]) continue;
        sumsize=size[z]; root=0;
        get_root(z,0);solve(root);
    } 
}

int main() {
    read(n); read(m);
    int x,y,z;
    For(i,1,n-1) {
        read(x); read(y); read(z);
        add(x,y,z);
    }
    For(i,1,m) read(p[i]);
    son[root=0]=sumsize=n; get_root(1,0); solve(root);
    For(i,1,m) printf(ans[i]? "AYE
":"NAY
");
    return 0;
}

  

bzoj2152聪聪可可

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=4e4+7;
int n,root,vis[maxn],nowsum;
 
char cc; ll ff;
template<typename T>void read(T& aa) {
    aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}
 
ll gcd(ll x,ll y) {
    return y==0? x:gcd(y,x%y);
}
 
int fir[maxn],nxt[2*maxn],to[2*maxn],e=0,v[2*maxn];
void add(int x,int y,int z) {
    to[++e]=y;nxt[e]=fir[x];fir[x]=e;v[e]=z%3;
    to[++e]=x;nxt[e]=fir[y];fir[y]=e;v[e]=z%3;
}
 
int son[maxn],size[maxn];
void get_root(int pos,int f) {
    size[pos]=1; son[pos]=0; int y,z;
    for(y=fir[pos];y;y=nxt[y]) {
        if((z=to[y])==f||vis[z]) continue;
        get_root(z,pos);
        size[pos]+=size[z];
        if(size[z]>=son[pos]) son[pos]=size[z];
    }
    son[pos]=max(son[pos],nowsum-size[pos]);
    if(son[pos]<son[root]) root=pos;
}
 
ll ans;
ll now[10],tot[10],t;
void dfs(int pos,int f,int x) {
    ++now[x]; int y,z;
    ans+=2*tot[(3-x)%3];
    for(y=fir[pos];y;y=nxt[y]) {
        if(vis[z=to[y]]||z==f) continue;
        dfs(z,pos,(x+v[y])%3);
    }
}
 
void solve(int pos) {
    vis[pos]=1; int y,z;
    memset(tot,0,sizeof(tot)); tot[0]=1;
    for(y=fir[pos];y;y=nxt[y]) {
        if(vis[z=to[y]]) continue;
        dfs(z,pos,v[y]%3);
        For(i,0,2) tot[i]+=now[i],now[i]=0;
    }
    for(y=fir[pos];y;y=nxt[y]) {
        if(vis[z=to[y]]) continue;
        nowsum=size[z]; root=0;
        get_root(z,pos); solve(root);
    }
}
 
int main() {
    read(n); int x,y,z; ans=n;
    For(i,1,n-1) {
        read(x); read(y); read(z);
        add(x,y,z);
    }
    size[0]=son[0]=nowsum=n;
    get_root(1,0); solve(root);
    ll r=n*n;ll p=gcd(ans,r);
    ans/=p; r/=p;
    printf("%lld/%lld",ans,r);
    return 0;
}

  

bzoj3648寝室管理

裸的点分治,环的处理就是直接把环跑一遍就可以了。

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=1e5+7;
int n,m,k,A,B,root,SUM;
ll ans;

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

int f[maxn];
int find(int x){return x==f[x]? x:f[x]=find(f[x]);}

int fir[maxn],nxt[2*maxn],to[2*maxn],e=0;
void add(int x,int y) {
	to[++e]=y;nxt[e]=fir[x];fir[x]=e;
	to[++e]=x;nxt[e]=fir[y];fir[y]=e;
}

int sz[maxn];
void chge(int pos,int x) {
	while(pos<=n) {
		sz[pos]+=x;
		pos+=pos&-pos;
	}
}

int q(int pos) {
	ll rs=0;
	while(pos) {
		rs+=sz[pos];
		pos-=pos&-pos;
	}
	return rs;
}

int size[maxn],U[maxn];bool vis[maxn];
void get_root(int pos,int f) {
	int y,z;U[pos]=0;size[pos]=1;
	for(y=fir[pos];y;y=nxt[y]) {
		if((z=to[y])==f||vis[z]) continue;
		get_root(z,pos);
		size[pos]+=size[z];
		U[pos]=max(U[pos],size[z]);
	}
	U[pos]=max(U[pos],SUM-size[pos]);
	if(U[pos]<U[root]) root=pos;
}

int zz[maxn],s,t;
void dfs(int pos,int f,int d,int dd) {//d:push dd:query
	zz[++t]=d; int y,z;
	ans+=(ll)q(n)-q(max(k-dd-1,0));
	for(y=fir[pos];y;y=nxt[y]) {
		if((z=to[y])==f||vis[z]) continue;
		dfs(z,pos,d+1,dd+1);
	}
}

void solve(int pos) {
	vis[pos]=1; int y,z;
	zz[s=t=1]=1;chge(1,1);
	for(y=fir[pos];y;y=nxt[y]) {
		if(vis[z=to[y]]) continue;
		dfs(z,pos,2,1);
		For(i,s+1,t) chge(zz[i],1);
		s=t;
	}
	For(i,1,t) chge(zz[i],-1);
	for(y=fir[pos];y;y=nxt[y]) {
		if(vis[z=to[y]]) continue;
		SUM=size[z]; root=0; get_root(z,pos);
		solve(root);
	}
}

int h[maxn],tot;
bool get_h(int pos,int f) {
	h[++tot]=pos; int y,z;
	if(pos==B) return vis[pos]=1;
	for(y=fir[pos];y;y=nxt[y]) {
		if((z=to[y])==f) continue;
		if(get_h(z,pos)) return vis[pos]=1;
	}
	tot--;
	return 0;
}

void get_ans() {
	memset(vis,0,sizeof(vis));
	tot=0;s=t=0; get_h(A,0);
	For(r,1,tot) {
		dfs(h[r],0,r,tot-r+1);
		For(i,s+1,t) chge(zz[i],1);
		s=t;
	}
}

int main() {
	read(n); read(m); read(k);
	int x,y;
	For(i,1,n) f[i]=i;
	For(i,1,m) {
		read(x); read(y);
		if(find(x)==find(y)) A=x,B=y;
		else {
			f[find(x)]=find(y);
			add(x,y);
		}
	}
	U[0]=n+1; SUM=n; 
	get_root(1,0); solve(root);
	if(n==m) get_ans();
	printf("%lld",ans);
	return 0;
}
/*
5 5 2
1 3
2 4
3 5
4 1
5 2
*/

  

原文地址:https://www.cnblogs.com/Serene-shixinyi/p/8575588.html