zoukankan      html  css  js  c++  java
  • 点分治

    点分治

    可能有一些点分治的模板是(O(n^2))的,但是如果在每次计算时都重新计算一下当前枚举子树的重心,就可以使得复杂度为(O(nlogn))

    点分治能处理的问题:在树上对具有某些限定条件路径进行静态统计的算法。 当然如果要待修之类的话紫荆花之恋是一道不错的题,不刻意压行大概只需要写250行QAQ

    首先我们定一个顶点(怎么定等会儿说) 显然树上的路径分为两种:经过顶点的和不经过顶点的。令(q[i])表示节点(i)到这个顶点的距离。显然经过顶点的路径(i,j)长度为(q[i]+q[j]) 如果不经过顶点:我们可以在子树里面再找一个顶点,使得路径经过该顶点 这样又可以用经过顶点的公式来算了(但是显然需要重新计算(q))

    现在回到如何定一个顶点。如果我们令当前顶点的儿子为子树节点,如果是一条链的话,会慢到吃粑粑 为了使得树的儿子分布更均匀,我们可以考虑用当前子树的重心作为子树的顶点 这样递归深度不会超过(logn)层,因此时间复杂度也就保证了(O(nlogn))

    解决了分治之后,显然这道题就是一道水题了,然后就可以(对于大佬来说)秒切了 (可是我是蒟蒻,所以我不能秒切)

    我们用(q[i]) 来储存以当前枚举的顶点的子树的(dis)(judge[x])存储以当前顶点的子树中是否有长度为(x)的边 将询问离线一下(就差不多完了)

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int maxn=100010;
    const int inf=1e9;
    int read(){
    	int 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;
    }
    int n,m,tot,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1];
    bool visit[maxn],judge[maxn],ans[maxn];
    int size[maxn],root,maxx[maxn],shawn[maxn],mendes,sum,ques[maxn],dis[maxn];
    int q[maxn],tail,qaq;
    void add(int x,int y,int z){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;val[tot]=z;}
    void getroot(int x,int fa){
    	size[x]=1;int num=0;
    	for(int i=fir[x];i;i=nxt[i]){
    		int y=to[i];if(y==fa || visit[y]) continue;
    		getroot(y,x);size[x]+=size[y];
    		maxx[x]=max(maxx[x],size[y]);
    	}
    	maxx[x]=max(maxx[x],qaq-size[x]);
    	if(maxx[x]<maxx[root]) root=x;
    }
    void calc_dis(int x,int fa){
    	q[++tail]=dis[x];
    	for(int i=fir[x];i;i=nxt[i]){
    		int y=to[i];if(y==fa || visit[y]) continue;
    		dis[y]=dis[x]+val[i];calc_dis(y,x);
    	}
    }
    void work(int x){
    	int mendes=0;sum=0;
    	for(int i=fir[x];i;i=nxt[i]){
    		int y=to[i];if(visit[y]) continue;
    		tail=0;dis[y]=val[i];calc_dis(y,x);
    		for(int j=1;j<=tail;j++){
    			for(int k=1;k<=m;k++){
    				if(ques[k]>=q[j]){
    					ans[k]|=judge[ques[k]-q[j]];
    				}
    			}
    		}
    		for(int j=1;j<=tail;j++){
    			judge[q[j]]=true;shawn[++mendes]=q[j];
    		}
    	}
    	for(int i=1;i<=mendes;i++) judge[shawn[i]]=false;
    }
    void solve(int x){
    	visit[x]=true;judge[0]=true;
    	work(x);
    	for(int i=fir[x];i;i=nxt[i]){
    		int y=to[i];if(visit[y]) continue;
    		maxx[root=0]=inf;qaq=size[y];
    		getroot(y,x);solve(root);
    	}
    }
    int main(){
    	n=read();m=read();
    	for(int i=1,x,y,z;i<=n-1;i++){
    		x=read();y=read();z=read();
    		add(x,y,z);add(y,x,z);
    	}
    	for(int i=1;i<=m;i++) ques[i]=read();
    	maxx[0]=n;qaq=n;getroot(1,0);
    	solve(root);
    	for(int i=1;i<=m;i++)
    		ans[i]?printf("AYE
    "):printf("NAY
    ");
    	return 0;
    }
    
  • 相关阅读:
    win7(windows 7)系统下安装SQL2005(SQL Server 2005)图文教程( Win7 SQL Server2005 安装教程)
    PL/SQL -->隐式游标(SQL%FOUND)
    sql%found sql%notfound sql%rowcount sql%isopen
    C# WINFORM 窗体执行ORACLE存储过程 进行增删改查 自己编写借助网络(二)
    C# WINFORM 窗体执行ORACLE存储过程 进行增删改查 自己编写借助网络
    .net 接收存储过程的返回值 。。。。
    oracle-扫盲贴:存储过程实现增删改查
    sql加一个%号是什么意思
    关于ExecuteNonQuery执行存储过程的返回值 、、实例讲解存储过程的返回值与传出参数、、、C#获取存储过程的 Return返回值和Output输出参数值
    iOS网络请求之数据解析
  • 原文地址:https://www.cnblogs.com/mendessy/p/11822849.html
Copyright © 2011-2022 走看看