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

    参考博客:

    怎么做
    一些理解

    时间复杂度

    洛谷点分治模板

    每次对当前联通块get_root,以rt为根dfs计算经过当前rt的答案,然后把rt设为不可通过的障碍,就把子树分为了若干联通块,递归下去对每一个联通块也这样做。

    最多递归log层,每一层的节点数都是O(n)。时间复杂度O(nlogn)。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    const int K=10000007,N=10007,M=100;
    typedef long long LL;
    using namespace std;
    int n,m,nsz,rt,qs[M],bo[K],ok[N];
    
    template<typename T>void read(T &x)  {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int ecnt,fir[N],nxt[N<<1],to[N<<1],val[N<<1];
    void add(int u,int v,int w) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
    }
    
    int sz[N],vis[N],mxsz[N],dis[N],sta[N],tp;
    void dfs(int x,int fa,int top) {
        for(int i=1;i<=m;i++) 
            if(qs[i]>=dis[x]&&bo[qs[i]-dis[x]]==top) ok[i]=1;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[to[i]]) {
            sta[++tp]=to[i];
            dis[to[i]]=dis[x]+val[i];
            dfs(to[i],x,top);
            if(x==top) {
                while(tp) {
                    int y=sta[tp--];
                    bo[dis[y]]=top;
                }
            }
        }
    }
    
    void get_root(int x,int fa) {
        sz[x]=1; mxsz[x]=0;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[to[i]]){
            get_root(to[i],x);
            sz[x]+=sz[to[i]];
            mxsz[x]=max(mxsz[x],sz[to[i]]); 
        }
        mxsz[x]=max(mxsz[x],nsz-sz[x]);
        if(!rt||mxsz[x]<mxsz[rt]) rt=x;
    }
    
    void solve(int x) {
        vis[x]=1;
        bo[0]=x;
        dis[x]=0;
        dfs(x,0,x);
        for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
            rt=0; nsz=sz[to[i]];
            get_root(to[i],x); 
            solve(rt);
        }
    }
    
    int main() {
    #ifdef DEBUG
        freopen(".in","r",stdin);
        freopen(".out","w",stdout);
    #endif
        read(n); read(m);
        for(int i=1;i<n;i++) {
            int u,v,w;
            read(u); read(v); read(w);
            add(u,v,w); 
        }
        for(int i=1;i<=m;i++) read(qs[i]);
        get_root(1,0);
        solve(rt);
        for(int i=1;i<=m;i++) 
            if(ok[i]) puts("AYE");
            else puts("NAY");
        return 0;
    }
    View Code

     

    洛谷聪聪可可

    用刚才一模一样的方法。为了不统计一个子树里的路径,访问rt的一个子树是就把子树里的点全部暴力压进栈里,访问完了再更新rt的答案,然而比容斥跑得快些。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    const int N=20007;
    typedef long long LL;
    using namespace std;
    int n,nsz,rt,up,dn;
    
    template<typename T>void read(T &x)  {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int gcd(int a,int b) { return !b?a:gcd(b,a%b); }
    
    int ecnt,fir[N],nxt[N<<1],to[N<<1],val[N<<1];
    void add(int u,int v,int w) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
    }
    
    int sz[N],vis[N],mxsz[N],dis[N],sta[N],tp,bo[3];
    void dfs(int x,int fa,int top) {
        if(x==top) up+=bo[(3-dis[x])%3];
        else up+=bo[(3-dis[x])%3]*2;
        sz[x]=1;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[to[i]]) {
            sta[++tp]=to[i];
            dis[to[i]]=(dis[x]+val[i])%3;
            dfs(to[i],x,top);
            sz[x]+=sz[to[i]];
            if(x==top) {
                while(tp) {
                    int y=sta[tp--];
                    bo[dis[y]]++;
                }
            }
        }
    }
    
    void get_root(int x,int fa) {
        sz[x]=1; mxsz[x]=0;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[to[i]]){
            get_root(to[i],x);
            sz[x]+=sz[to[i]];
            mxsz[x]=max(mxsz[x],sz[to[i]]); 
        }
        mxsz[x]=max(mxsz[x],nsz-sz[x]);
        if(!rt||mxsz[x]<mxsz[rt]) rt=x;
    }
    
    void solve(int x) {
        vis[x]=1;
        bo[0]=1;
        bo[1]=bo[2]=0;
        dis[x]=0;
        dfs(x,0,x);
        for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
            rt=0; nsz=sz[to[i]];
            get_root(to[i],x); 
            solve(rt);
        }
    }
    
    int main() {
    #ifdef DEBUG
        freopen(".in","r",stdin);
        freopen(".out","w",stdout);
    #endif
        read(n);
        for(int i=1;i<n;i++) {
            int u,v,w;
            read(u); read(v); read(w);
            add(u,v,w); 
        }
        get_root(1,0);
        solve(rt);
        dn=n*n; 
        int d=gcd(up,dn);
        printf("%d/%d",up/d,dn/d);
        return 0;
    }
    View Code

    之前写的容斥的版本,感觉很不优秀啊。

    //Twenty
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<vector>
    const int maxn=20000+299;
    int ecnt,fir[maxn],nxt[maxn*2],to[maxn*2],val[maxn*2],vis[maxn],root,n; 
    int ans,f[5],sz[maxn],mx[maxn],sum,dis[maxn];
    using namespace std;
    int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
    void add(int u,int v,int w){
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w%3;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w%3;
    }
    void dfs(int x,int fa){
        f[dis[x]]++;
        for(int i=fir[x];i;i=nxt[i]){
            int v=to[i];
            if(vis[v]||v==fa) continue;
            dis[v]=(dis[x]+val[i])%3;
            dfs(v,x);
        }
    }
    int cul(int x,int d){
        dis[x]=d; 
        f[0]=f[1]=f[2]=0; 
        dfs(x,0);
        return f[0]*f[0]+f[1]*f[2]*2;
    }
    void get_root(int x,int fa){
        sz[x]=1; mx[x]=0;
        for(int i=fir[x];i;i=nxt[i]){
            int v=to[i];
            if(v==fa||vis[v]) continue;
            get_root(v,x);
            sz[x]+=sz[v]; mx[x]=max(mx[x],sz[v]);
        }
        mx[x]=max(mx[x],sum-sz[x]);
        if(mx[x]<mx[root]) root=x;
    }
    void work(int x){
        ans+=cul(x,0); vis[x]=1;
        for(int i=fir[x];i;i=nxt[i]){
            int v=to[i];
            if(vis[v]) continue;
            ans-=cul(v,val[i]);
            sum=sz[v];
            root=0; get_root(v,x);
            work(root);
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        mx[0]=n+1;
        sum=n;
        get_root(1,0);
        work(root);
        int t=gcd(n*n,ans);
        printf("%d/%d
    ",ans/t,n*n/t);
        return 0;
    }
    View Code
  • 相关阅读:
    unexpected inconsistency;run fsck manually esxi断电后虚拟机启动故障
    centos 安装mysql 5.7
    centos 7 卸载mysql
    centos7 在线安装mysql5.6,客户端远程连接mysql
    ubuntu 14.04配置ip和dns
    centos7 上搭建mqtt服务
    windows eclipse IDE打开当前类所在文件路径
    git 在非空文件夹clone新项目
    eclipse中java build path下 allow output folders for source folders 无法勾选,该如何解决 eclipse中java build path下 allow output folders for source folders 无法勾选,
    Eclipse Kepler中配置JadClipse
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8492087.html
Copyright © 2011-2022 走看看