zoukankan      html  css  js  c++  java
  • BZOJ 3697: 采药人的路径 [点分治] [我想上化学课]

    传送门

    题意:

    路径有$-1,1$两种权值,求有多少路径满足权值和为$0$且有一个点将路径分成权值和为$0$的两段


    第四节课本来想去上化学,然后快上课了这道题还没调出来.....可恶我想上化学

    昨天两节语文课潸然的李煜讲座也没去听呜呜听说今天的语文课还有什么文艺活动又错过了呜呜

    还是有思路的

    点分治,考虑经过$u$的路径

    首先保证权值和为$0$,记录$c[i]$为当前权值和为$i$的路径有几条

    怎么满足有一个点呢?

    $0+0=0$!!!

    我们只要保证一段和$0$另一段自然也是$0$

    所以补充保存的信息,

    $c[i][0]$当前权值和为$0$且到$u$的路径上没有一段为$0$(就是没有祖先的权值和也为$i$,打标记就行了)的路径有几条

    $c[i][1]$表示有......

    然后每颗子树先更新答案再更新$c$就行了

    然后一直$WA$.....

    突然想到自己没有处理$u$的信息

    然后改了也不对

    然后发现打标记只是$=1 =0$没有$++ --$.....

    改了还不对

    参考黄学长的代码打了一份他的做法$AC$了,然后又开始找自己的错误

    最后还是处理$u$的信息有问题,我直接用了$mark$因为我还以为$mark$只有$0,1$.......

    还我化学

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5,INF=1e9+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,a,b,w;
    struct edge{
        int v,w,ne;
    }e[N<<1];
    int h[N],cnt;
    inline void ins(int u,int v,int w){
        cnt++;
        e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
        cnt++;
        e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
    }
    
    int f[N],size[N],all,vis[N],root;
    void dfsRt(int u,int fa){
        size[u]=1;f[u]=0;
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]||v==fa) continue;
            dfsRt(v,u);
            size[u]+=size[v];
            f[u]=max(f[u],size[v]);
        }
        f[u]=max(f[u],all-size[u]);
        if(f[u]<f[root]) root=u;
    }
    int mark[N<<1],Z=N,c[N<<1][2];
    ll ans;
    void dfsAns(int u,int fa,int now){
        if(now==0) ans+=c[Z][0]+c[Z][1] +(mark[Z]>=1);
        else{
            if(mark[Z+now]) ans+=c[Z-now][0]+c[Z-now][1];
            else ans+=c[Z-now][1];
        }
        mark[Z+now]++;
        for(int i=h[u];i;i=e[i].ne)
            if(!vis[e[i].v]&&e[i].v!=fa) dfsAns(e[i].v,u,now+e[i].w);
        mark[Z+now]--;
    }
    int st[N],top;
    void dfsDee(int u,int fa,int now){
        c[Z+now][mark[Z+now]>=1]++;
        st[++top]=Z+now;
        mark[Z+now]++;
        for(int i=h[u];i;i=e[i].ne)
            if(!vis[e[i].v]&&e[i].v!=fa) dfsDee(e[i].v,u,now+e[i].w);
        mark[Z+now]--;
    }
    void dfsSol(int u){
        vis[u]=1;
        for(int i=h[u];i;i=e[i].ne)
            if(!vis[e[i].v]) dfsAns(e[i].v,u,e[i].w),dfsDee(e[i].v,u,e[i].w);
    
        while(top) c[st[top]][0]=c[st[top]][1]=0,top--;
        for(int i=h[u];i;i=e[i].ne) 
            if(!vis[e[i].v]){
                all=size[e[i].v];root=0;
                dfsRt(e[i].v,0);
                dfsSol(root);
            }
    }
    int main(){
        freopen("in","r",stdin);
        n=read();
        for(int i=1;i<n;i++) a=read(),b=read(),w= read()==0?-1:1,ins(a,b,w);
        all=n;root=0;f[0]=INF;
        dfsRt(1,0);
        dfsSol(root);
        printf("%lld",ans);
    }

    黄学长做法,本质上一样的

    改进了一下后$1600ms$

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5,INF=1e9+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,a,b,w;
    struct edge{
        int v,w,ne;
    }e[N<<1];
    int h[N],cnt;
    inline void ins(int u,int v,int w){
        cnt++;
        e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
        cnt++;
        e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
    }
    
    int f[N],size[N],all,vis[N],root;
    void dfsRt(int u,int fa){
        size[u]=1;f[u]=0;
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]||v==fa) continue;
            dfsRt(v,u);
            size[u]+=size[v];
            f[u]=max(f[u],size[v]);
        }
        f[u]=max(f[u],all-size[u]);
        if(f[u]<f[root]) root=u;
    }
    int mark[N<<1],Z=N;
    ll c[N<<1][2],d[N<<1][2];
    ll ans;
    int mx;
    void dfsRun(int u,int fa,int now){
        d[Z+now][mark[Z+now]>=1]++;
        mx=max(mx,abs(now));
        mark[Z+now]++;
        for(int i=h[u];i;i=e[i].ne)
            if(!vis[e[i].v]&&e[i].v!=fa) 
                dfsRun(e[i].v,u,now+e[i].w);
        mark[Z+now]--;
    }
    void dfsSol(int u){//printf("dfsSol %d
    ",u);
        vis[u]=1;
        c[Z][0]=1;
        int mxmx=0;
        for(int i=h[u];i;i=e[i].ne)
            if(!vis[e[i].v]){
                mx=1;
                dfsRun(e[i].v,u,e[i].w);
                mxmx=max(mxmx,mx);
                ans+=(c[Z][0]-1)*d[Z][0];
                for(int j=-mx;j<=mx;j++) 
                    ans+=c[Z-j][1]*d[Z+j][1]+
                        c[Z-j][0]*d[Z+j][1]+c[Z-j][1]*d[Z+j][0];
                for(int j=Z-mx;j<=Z+mx;j++){
                    c[j][0]+=d[j][0];
                    c[j][1]+=d[j][1];
                    d[j][0]=d[j][1]=0;
                }
            }
        for(int i=Z-mxmx;i<=Z+mxmx;i++) c[i][0]=c[i][1]=0;
        for(int i=h[u];i;i=e[i].ne) 
            if(!vis[e[i].v]){
                all=size[e[i].v];root=0;
                dfsRt(e[i].v,0);
                dfsSol(root);
            }
    }
    int main(){
        freopen("in","r",stdin);
        n=read();
        for(int i=1;i<n;i++) a=read(),b=read(),w= read()==0?-1:1,ins(a,b,w);
        all=n;root=0;f[0]=INF;
        dfsRt(1,0);
        dfsSol(root);
        printf("%lld",ans);
    }
  • 相关阅读:
    如何解决移动端滚动穿透问题
    如何在mac中通过命令行使用sublime
    正向代理和反向代理
    UTF8、UTF16、UTF16-LE、UTF16-BE、UTF32都是些什么?
    依赖的版本
    如何移除inline-block元素之间的空白
    如何用JavaScript重定向到另一个网页?
    [读书笔记] 高性能网站建设指南
    java使用jconsole查看java程序运行(jmx原理)
    oracle相关知识点
  • 原文地址:https://www.cnblogs.com/candy99/p/6497858.html
Copyright © 2011-2022 走看看