zoukankan      html  css  js  c++  java
  • 树分治---点分治(挑战p360)

    poj1741

    题:http://poj.org/problem?id=1741

    题意:给定树,和一个树k,问有多少个点对之间的路径是不超过k

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    int ans=0,tot,maxx,root;
    const int M=1e4+4;
    struct node{
        int v,w,nextt;
    }e[M<<1];
    int head[M],vis[M],sz[M],maxv[M],num,dis[M],n,k;
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
    }
    void dfssz(int u,int f){
        sz[u]=1;
        maxv[u]=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;//cout<<"!!"<<endl;
            if(v==f||vis[v])
                continue;
            dfssz(v,u);
            sz[u]+=sz[v];
            maxv[u]=max(maxv[u],sz[v]);
        }
    }
    void dfsroot(int r,int u,int f){
        maxv[u]=max(maxv[u],sz[r]-sz[u]);
        if(maxv[u]<maxx){
            maxx=maxv[u];
            root=u;
        }
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(vis[v]||v==f)
                continue;
            dfsroot(r,v,u);
        }
    }
    void dfsdis(int u,int d,int f){
        dis[num++]=d;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v==f||vis[v])
                continue;
            dfsdis(v,d+e[i].w,u);
        }
    }
    int cal(int u,int d){
        int sum=0;
        num=0;
        dfsdis(u,d,-1);
        sort(dis,dis+num);
        int i=0,j=num-1;
        while(i<j){
            while(dis[i]+dis[j]>k&&i<j){
                j--;
            }
            sum+=j-i;
            i++;
        }
        return sum;
    }
    void solve(int u){
        maxx=n;
        dfssz(u,-1);
        dfsroot(u,u,-1);
        ans+=cal(root,0);
        
        vis[root]=1;
        for(int i=head[root];~i;i=e[i].nextt){
            int v=e[i].v;
            if(vis[v])
                continue;
            ans-=cal(v,e[i].w);
            solve(v);
        }
    }
    int main(){
        while(~scanf("%d%d",&n,&k)&&(n+k)){
            tot=0,ans=0;
            memset(head,-1,sizeof(head));
            memset(vis,0,sizeof(vis));
            for(int i=1;i<n;i++){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                addedge(u,v,w);
                addedge(v,u,w);
            }
            
            solve(1);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    poj1987

    题:http://poj.org/problem?id=1987

    和上面一样的题意,不一样的写法

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<cmath>
    using  namespace std;
    const int M=2e5+5;
    const int inf=0x3f3f3f3f;
    typedef long long ll;
    char s[2];
    ll ans;
    int num,n,m;
    ll sz[M],maxv[M],dis[M],k;
    int maxx,vis[M],head[M],reco,total,tot,root;
    struct node{
        int v,nextt;
        ll w;
    }e[M<<1];
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
    }
    void addedge(int u,int v){
        e[tot].v=v;
        e[tot].nextt=head[u];
        head[u]=tot++;
    }
    
    void dfsroot(int u,int f){
        sz[u]=1;
        ll maxson=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                dfsroot(v,u);
                sz[u]+=sz[v];
                maxson=max(maxson,sz[v]);
            }
        }
        maxson=max(maxson,total-sz[u]);
        if(maxson<reco)
            root=u,reco=maxson;
    }
    
    void dfsdis(int u,int f,ll d){
        dis[num++]=d;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v==f||vis[v])
                continue;
            dfsdis(v,u,d+e[i].w);
        }
    }
    ll cal(int u,int f,ll d){
        ll sum=0;
        num=0;
        dfsdis(u,f,d);
        sort(dis,dis+num);
        int i=0,j=num-1;
        while(i<j){
            while(dis[i]+dis[j]>k&&i<j){
                j--;
            }
            sum+=1ll*(j-i);
            i++;
        }
        return sum;
    }
    void doit(int u,int f){
        ///跨越u的路径和在同一个子树中的路径
        ans+=cal(u,f,0);
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
    ///因为同一个子树中的路径在dfs下去的时候会被算到,所以要减去被预先算过的
            if(v!=f&&!vis[v]){
                ans-=cal(v,u,e[i].w);
            }
        }
    }
    void solve(int u,int f){
        vis[u]=1;
        doit(u,f);
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                total=sz[v];
                reco=inf;
                dfsroot(v,u);
                solve(root,0);
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        while(m--){
            int u,v;
            ll w;
            scanf("%d%d%lld%s",&u,&v,&w,s);
    
            addedge(u,v,w);
            addedge(v,u,w);
        }
        scanf("%lld",&k);
        total=n;
        reco=inf;
        dfsroot(1,0);
        solve(root,0);
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

     题:https://www.luogu.org/problem/P4149

    题意:给定固定路径长,边数最少路径

    #include<bits/stdc++.h>
    using namespace std;
    const int M=2e5+5;
    const int inf=0x3f3f3f3f;
    const int N=1e6+6;
    int vis[M],temp[N],sz[M],head[M];
    int n,k,total,reco,root;
    int ans,tot;
    #define pb push_back
    struct node{
        int u,v,w,nextt;
    }e[M<<1];
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
    }
    void dfsroot(int u,int f){
        int maxx=0;
        sz[u]=1;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                dfsroot(v,u);
                sz[u]+=sz[v];
                maxx=max(maxx,sz[v]);
            }
        }
        maxx=max(maxx,total-sz[u]);
        if(reco>maxx)
            reco=maxx,root=u;
    }
    void cal(int u,int f,int d,int num){
        if(d>k)
            return ;
        ans=min(ans,temp[k-d]+num);
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                cal(v,u,d+e[i].w,num+1);
            }
        }
    }
    void update(int u,int f,int d,int num){
        if(d>k)
            return ;
        temp[d]=min(temp[d],num);
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                update(v,u,d+e[i].w,num+1);
            }
        }
    }
    void Clear(int u,int f,int d){
        if(d>=k)
            return ;
        temp[d]=inf;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                Clear(v,u,d+e[i].w);
            }
        }
    }
    void dfs1(int u,int f){
        sz[u]=1;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                dfs1(v,u);
            }
        }
    }
    void doit(int u,int f){
        dfs1(u,f);
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                cal(v,u,e[i].w,1);
                update(v,u,e[i].w,1);
            }
        }
        Clear(u,f,0);
    }
    void solve(int u,int f){
        vis[u]=1;
        temp[0]=0;
        doit(u,f);
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                total=sz[v];
                reco=inf;
                dfsroot(v,u);
                solve(root,0);
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=0;i<=n;i++)
            head[i]=-1;
        for(int i=0;i<=k;i++)
            temp[i]=inf;
        for(int u,v,w,i=1;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            u++,v++;
            addedge(u,v,w);
            addedge(v,u,w);
        }
        total=n;
        reco=inf;
        ans=inf;
        dfsroot(1,0);
        solve(root,0);
        if(ans==inf)
            puts("-1");
        else
            printf("%d
    ",ans);
        return 0;
    }
    View Code

     题(求点权处理的题):http://acm.hdu.edu.cn/showproblem.php?pid=4812

    题意:给定一棵 n 个点的树,每个点有权值 Vi,问是否存在一条路径使得路径上所有点的权值乘积 mod(10^6 + 3) 为 K,输出路径的首尾标号,若有多解,输出字典序最小的解

    注意:更新就更新以重点为起点的路径,枚举答案时则用以重点孩子为起点的路径

    除法,逆元处理

    #pragma comment(linker,"/STACK:102400000,102400000")
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define pb push_back
    typedef long long ll;
    const int M=1e5+5;
    const int mod=1e6+3;
    const int inf=0x3f3f3f3f;
    int reco,total,root,n;
    ll k;
    ll sz[M],a[M],vis[M];
    int ansi,ansj;
    int temp[mod+6];
    struct node{
        int v,nextt;
    }e[M<<1];
    int head[M];
    int tot;
    int inv[mod+6];
    void addedge(int u,int v){
        e[tot].v=v;
        e[tot].nextt=head[u];
        head[u]=tot++;
    }
    void iniInv(){
        inv[1]=1;
        for(int i=2;i<mod;i++)
            inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
    }
    void dfsroot(int u,int f){
        sz[u]=1;
        ll maxson=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                dfsroot(v,u);
                sz[u]+=sz[v];
                maxson=max(maxson,sz[v]);
            }
        }
        maxson=max(maxson,total-sz[u]);
        if(maxson<reco)
            root=u,reco=maxson;
    }
    void up(int x,int y){
        int minn=min(x,y);
        int maxx=max(x,y);
        if(minn<ansi){
            ansi=minn,ansj=maxx;
        }
        else if(minn==ansi){
            if(maxx<ansj)
                ansj=maxx;
        }
    }
    void cal(int u,int f,int d){
        int x=temp[k*inv[d]%mod];
        if(x)
            up(u,x);
    
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                cal(v,u,d*a[v]%mod);
            }
        }
    }
    void update(int u,int f,int d){
        if(!temp[d])
            temp[d]=u;
        else
            temp[d]=min(temp[d],u);
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                update(v,u,d*a[v]%mod);
            }
        }
    }
    void del(int u,int f,int d){
        temp[d]=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                del(v,u,d*a[v]%mod);
            }
        }
    }
    void doit(int u,int f){
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]){
                cal(v,u,a[v]);
                update(v,u,a[u]*a[v]%mod);
            }
        }
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]){
                del(v,u,a[u]*a[v]%mod);
            }
        }
    }
    void solve(int u,int f){
        vis[u]=1;
        temp[a[u]]=u;
        doit(u,f);
        temp[a[u]]=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&v!=f){
                reco=inf;
                total=sz[v];
                dfsroot(v,u);
                solve(root,0);
            }
        }
    }
    int main(){
    //    freopen("in","r",stdin);
        iniInv();
    
        while(scanf("%d%lld",&n,&k)!=EOF){
            tot=0;
            memset(head,-1,sizeof(head));
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]),vis[i]=0;
            memset(temp,0,sizeof(temp));
    
            for(int u,v,i=1;i<n;i++){
                scanf("%d%d",&u,&v);
                addedge(u,v);
                addedge(v,u);
            }
            ansi=ansj=inf;
            reco=inf;
            total=n;
            dfsroot(1,0);
            solve(root,0);
            if(ansi==inf){
                puts("No solution");
            }
            else{
                printf("%d %d
    ",ansi,ansj);
            }
        }
        return 0;
    }
    View Code

    bzoj 2152

    题:https://www.lydsy.com/JudgeOnline/problem.php?id=2152

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int M=2e4+4;
    struct node{
        int v,nextt;
        int w;
    }e[M<<1];
    int head[M],dis[4],sz[M],maxv[M],vis[M],n,tot,fenzi,maxx,root;
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].nextt=head[u];
        e[tot].w=w;
        head[u]=tot++;
    }
    void dfssz(int u,int f){
        maxv[u]=0;
        sz[u]=1;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v==f||vis[v])
                continue;
            dfssz(v,u);
            sz[u]+=sz[v];
            maxv[u]=max(maxv[u],sz[v]);
        }
    }
    void dfsroot(int r,int u,int f){
        maxv[u]=max(maxv[u],sz[r]-sz[u]);
        if(maxx>maxv[u]){
            maxx=maxv[u];
            root=u;
        }
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v==f||vis[v])
                continue;
            dfsroot(r,v,u);
        }
    }
    void dfsdis(int u,int f,int d){
        dis[d%3]++;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(vis[v]||v==f)
                continue;
            dfsdis(v,u,(d+e[i].w)%3);
        }
    }
    ll cal(int u,int d){
        dis[0]=dis[1]=dis[2]=0;
        dfsdis(u,-1,d);
        ll sum=0;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                if((i+j)%3==0)
                    sum+=dis[i]*dis[j];
        return sum;     
    }
    void solve(int u){
        maxx=n;
        dfssz(u,-1);
        dfsroot(u,u,-1);
        fenzi+=cal(root,0);
        vis[root]=1;
        for(int i=head[root];~i;i=e[i].nextt){
            int v=e[i].v;
            if(vis[v])
                continue;
            fenzi-=cal(v,e[i].w);
            solve(v);
        }
    }
    int main(){
        scanf("%d",&n);
        memset(head,-1,sizeof(head));
        for(int i=1;i<n;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        solve(1);
        int fenmu=n*n;
        //cout<<fenmu<<endl;
        int g=__gcd(fenzi,fenmu);
        printf("%d/%d",fenzi/g,fenmu/g);
        return 0;
    }
    View Code

     题:https://ac.nowcoder.com/acm/contest/1099/I

    题意:找出路径和为2019倍数的路径

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    ll ans=0;
    int tot,maxx,root;
    const int M=2e4+5;
    struct node{
        int v,w,nextt;
    }e[M<<1];
    int head[M],vis[M],sz[M],maxv[M],dis[2020],n;
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
    }
    void dfssz(int u,int f){
        sz[u]=1;
        maxv[u]=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;//cout<<"!!"<<endl;
            if(v==f||vis[v])
                continue;
            dfssz(v,u);
            sz[u]+=sz[v];
            maxv[u]=max(maxv[u],sz[v]);
        }
    }
    void dfsroot(int r,int u,int f){
        maxv[u]=max(maxv[u],sz[r]-sz[u]);
        if(maxv[u]<maxx){
            maxx=maxv[u];
            root=u;
        }
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(vis[v]||v==f)
                continue;
            dfsroot(r,v,u);
        }
    }
    void dfsdis(int u,int d,int f){
        dis[d%2019]++;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v==f||vis[v])
                continue;
            dfsdis(v,(d+e[i].w)%2019,u);
        }
    }
    ll cal(int u,int d){
        ll sum=0;
        for(int i=0;i<=2019;i++)
            dis[i]=0;
        dfsdis(u,d,-1);
        for(int i=0;i<2019;i++){
            if(dis[i]==0||dis[(2019-i)%2019]==0)
                continue;
            sum+=1ll*dis[i]*(dis[(2019-i)%2019]);
        }
       // mp.clear();
        return sum;
    }
    void solve(int u){
        maxx=n;
        dfssz(u,-1);
        dfsroot(u,u,-1);
        ans+=cal(root,0);
        
        vis[root]=1;
        for(int i=head[root];~i;i=e[i].nextt){
            int v=e[i].v;
            if(vis[v])
                continue;
            ans-=cal(v,e[i].w);
            solve(v);
        }
    }
    int main(){
        while(~scanf("%d",&n)){
            tot=0,ans=0ll;
            memset(head,-1,sizeof(head));
            memset(vis,0,sizeof(vis));
            for(int i=1;i<n;i++){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                addedge(u,v,w);
                addedge(v,u,w);
            }
            
            solve(1);
            printf("%lld
    ",(ans-n)/2);//要减去自己到自己的贡献 
        }
        return 0;
    }
    View Code

     点分治好题:https://www.luogu.org/problem/P2664

    最终思考于:https://blog.csdn.net/wu_tongtong/article/details/78963542

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int M=2e5+5;
    int reco,total;
    ll sz[M];
    int head[M],C[M],vis[M],cnt[M],maxv[M],n,tot,root,num,sum,tt;
    ll ans[M],col[M];
    struct node{
        int v,nextt;
    }e[M<<1];
    void addedge(int u,int v){
        e[tot].v=v;
        e[tot].nextt=head[u];
        head[u]=tot++;
    }
    void dfsroot(int u,int f){
        sz[u]=1;
        ll maxson=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                dfsroot(v,u);
                sz[u]+=sz[v];
                maxson=max(maxson,sz[v]);
            }
        }
        maxson=max(maxson,total-sz[u]);
        if(maxson<reco)
            root=u,reco=maxson;
    }
    void dfs1(int u,int f){
        sz[u]=1;
        cnt[C[u]]++;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                dfs1(v,u);
                sz[u]+=sz[v];
            }
        }
        if(cnt[C[u]]==1){
            sum+=sz[u];
            col[C[u]]+=sz[u];
        }
        cnt[C[u]]--;
        
    }
    void change(int u,int f,int sign){
        cnt[C[u]]++;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v])
                change(v,u,sign);
        }
        if(cnt[C[u]]==1){
            sum+=1ll*sign*sz[u];
            col[C[u]]+=1ll*sign*sz[u];
        }
        cnt[C[u]]--;
    }
    void dfs2(int u,int f){
        cnt[C[u]]++;
        if(cnt[C[u]]==1){
            sum-=col[C[u]];
            num++;
        }
        ans[u]+=1ll*sum+num*tt;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                dfs2(v,u);
            }
        }
        if(cnt[C[u]]==1){
            sum+=col[C[u]];
            num--;
        }
        cnt[C[u]]--;
    }
    void cle(int  u,int f){
        cnt[C[u]]=0;
        col[C[u]]=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v])
                cle(v,u);    
        }
    }
    void doit(int u,int f){
        dfs1(u,f);
        ans[u]+=(ll)sum;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                cnt[C[u]]++;
                col[C[u]]-=sz[v];
                sum-=sz[v];
                change(v,u,-1);
                cnt[C[u]]--;
                
                tt=sz[u]-sz[v];
                dfs2(v,u);
                
                cnt[C[u]]++;
                col[C[u]]+=sz[v];
                sum+=sz[v];
                change(v,u,1);
                cnt[C[u]]--;
            }
        }
        sum=num=0;
        cle(u,f);
    }
    void solve(int u,int f){
        
        vis[u]=1;
        doit(u,f);
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(v!=f&&!vis[v]){
                total=sz[v];
                reco=inf;
                dfsroot(v,u);
                solve(root,0);
            }
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=0;i<=n;i++)
            head[i]=-1;
        for(int i=1;i<=n;i++)
            scanf("%d",&C[i]);
        for(int u,v,i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        total=n;
        reco=inf;
        dfsroot(1,0);
        solve(root,0);
        for(int i=1;i<=n;i++)
            printf("%lld
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    2、从0开始学算法 时间/空间复杂度(如何知道你的代码性能如何?)
    1、从0开始学算法 概述
    机器学习(五):通俗易懂决策树与随机森林及代码实践
    机器学习(四):通俗理解支持向量机SVM及代码实践
    机器学习(三):理解逻辑回归及二分类、多分类代码实践
    HDU 2492 Ping pong (树状数组)
    yum更新失败
    webpack3配置rules的问题
    置顶帖汇总
    2021.07.03软件更新公告
  • 原文地址:https://www.cnblogs.com/starve/p/11562899.html
Copyright © 2011-2022 走看看