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
  • 相关阅读:
    服务器键盘设置错误 完美解决
    windows 彻底删除360文件 360zipext.dll 等等
    VS2005智能设备中无法找到PInvoke DLL
    如何使用DotNet 2.0中的应用程序配置 Settings.settings
    维护应用程序状态(一):使用浏览器cookie
    NHibernate学习导航
    HTML基础(三):基本的HTML标签
    使用Cookie对象保存用户自定义设置
    ASP.NET2.0 个性化用户配置
    sealed修饰符的使用
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8492087.html
Copyright © 2011-2022 走看看