• FR #2题解


    A.

      考虑把(u,v)的询问离线挂在u上,然后dfs,每次从fath[x]到[x]相当于x子树dis区间加1,x子树以外区间-1,然后维护区间和区间平方和等。

          常数略大。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define maxv 100500
    #define maxe 200500
    using namespace std;
    long long n,fath[maxv],q,uu,vv,dis[maxv],l[maxv],r[maxv],times=0,fdfn[maxv],g[maxv],nume=1,ans[maxv],cnt;
    long long tot=0,root,ls[maxv<<2],rs[maxv<<2],val1[maxv<<2],val2[maxv<<2],lazy[maxv<<2];
    vector <long long> v[maxv],id[maxv];
    bool vis[maxv];
    struct edge
    {
        long long v,nxt;
    }e[maxe];
    long long read()
    {
        char ch;long long data=0;
        while (ch<'0' || ch>'9') ch=getchar();
        while (ch>='0' && ch<='9')
        {
            data=data*10+ch-'0';
            ch=getchar();
        }
        return data;
    }
    void addedge(long long u,long long v)
    {
        e[++nume].v=v;e[nume].nxt=g[u];g[u]=nume;
        e[++nume].v=u;e[nume].nxt=g[v];g[v]=nume;
    }
    void pushup(long long now,long long left,long long right)
    {
        val1[now]=val1[ls[now]]+val1[rs[now]];
        val2[now]=val2[ls[now]]+val2[rs[now]];
    }
    void pushdown(long long now,long long left,long long right)
    {
        if (!lazy[now]) return;
        long long mid=left+right>>1,d=lazy[now],ll=mid-left+1,rr=right-mid;
        val1[ls[now]]+=2*d*val2[ls[now]]+d*d*ll;val1[rs[now]]+=2*d*val2[rs[now]]+d*d*rr;
        val2[ls[now]]+=d*ll;val2[rs[now]]+=d*rr;
        lazy[ls[now]]+=d;lazy[rs[now]]+=d;
        lazy[now]=0;
    }
    void build(long long &now,long long left,long long right)
    {
        now=++tot;lazy[now]=0;
        if (left==right)
        {
            val1[now]=dis[fdfn[left]]*dis[fdfn[left]];val2[now]=dis[fdfn[left]];
            return;
        }
        long long mid=left+right>>1;
        build(ls[now],left,mid);
        build(rs[now],mid+1,right);
        pushup(now,left,right);
    }
    long long ask(long long now,long long left,long long right,long long l,long long r)
    {
        pushdown(now,left,right);
        if ((left==l) && (right==r)) return val1[now];
        long long mid=left+right>>1;
        if (r<=mid) return ask(ls[now],left,mid,l,r);
        else if (l>=mid+1) return ask(rs[now],mid+1,right,l,r);
        else return ask(ls[now],left,mid,l,mid)+ask(rs[now],mid+1,right,mid+1,r);
    }
    void modify(long long now,long long left,long long right,long long l,long long r,long long val)
    {
        if (l>r) return;
        pushdown(now,left,right);
        if ((left==l) && (right==r)) 
        {
            lazy[now]+=val;
            val1[now]+=2*val*val2[now]+val*val*(right-left+1);val2[now]+=val*(right-left+1);
            return;
        }
        long long mid=left+right>>1;
        if (r<=mid) modify(ls[now],left,mid,l,r,val);
        else if (l>=mid+1) modify(rs[now],mid+1,right,l,r,val);
        else
        {
            modify(ls[now],left,mid,l,mid,val);
            modify(rs[now],mid+1,right,mid+1,r,val);
        }
        pushup(now,left,right);
    }
    void get_ans(long long x)
    {
        for (long long i=0;i<v[x].size();i++)
            ans[id[x][i]]=ask(root,1,n,l[v[x][i]],r[v[x][i]]);
    }
    void modify_tree(long long x,long long f)
    {
        modify(root,1,n,l[x],r[x],-f);
        modify(root,1,n,1,l[x]-1,f);
        modify(root,1,n,r[x]+1,n,f);
    }
    void dfs1(long long x)
    {
        l[x]=r[x]=++times;fdfn[times]=x;
        for (long long i=g[x];i;i=e[i].nxt)
        {
            long long v=e[i].v;
            if (v!=fath[x])
            {
                dis[v]=dis[x]+1;
                dfs1(v);
                r[x]=max(r[x],r[v]);
            }
        }
    }
    void dfs2(long long x)
    {
        get_ans(x);
        for (long long i=g[x];i;i=e[i].nxt)
        {
            long long v=e[i].v;
            if (v!=fath[x])
            {
                modify_tree(v,1);
                dfs2(v);
                modify_tree(v,-1);
            }
        }
    }
    int main()
    {
        n=read();
        for (long long i=1;i<=n-1;i++) {fath[i+1]=read();addedge(fath[i+1],i+1);}
        q=read();
        for (long long i=1;i<=q;i++)
        {
            uu=read();vv=read();
            v[uu].push_back(vv);id[uu].push_back(i);
        }
        dfs1(1);build(root,1,n);
        dfs2(1);
        for (long long i=1;i<=q;i++) printf("%lld
    ",ans[i]);
        return 0;
    }

    B.

      我们发现k=0的时候可以o(1)计算(毕竟是01序列)。当k>=1的时候可以证明答案是ceil(l/2)*trunc(l/2)。

         要善于猜结论啊。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 500500
    using namespace std;
    long long n,q,a[maxn],s1[maxn],s[maxn],x[maxn],y[maxn],k[maxn],cnt[2][maxn],ans[maxn],tab[maxn];
    long long read()
    {
        char ch;long long data=0;
        while (ch<'0' || ch>'9') ch=getchar();
        while (ch>='0' && ch<='9')
        {
            data=data*10+ch-'0';
            ch=getchar();
        }
        return data;
    }
    void calc(long long type,long long pos)
    {
        cnt[0][0]=1;tab[0]=0;
        for (long long i=1;i<=n;i++)
        {
            cnt[0][i]=cnt[0][i-1];cnt[1][i]=cnt[1][i-1];
            if (!s[i]) cnt[0][i]++;
            else cnt[1][i]++;
            tab[i]=tab[i-1]+cnt[s[i]^1][i];
        }
        if (!type)
        {
            for (long long i=1;i<=n;i++)
            {
                if (x[i]>=2) ans[i]=(cnt[1][y[i]-1]-cnt[1][x[i]-2])*cnt[0][y[i]]+(cnt[0][y[i]-1]-cnt[0][x[i]-2])*cnt[1][y[i]]-(tab[y[i]-1]-tab[x[i]-2]);
                else ans[i]=cnt[1][y[i]-1]*cnt[0][y[i]]+cnt[0][y[i]-1]*cnt[1][y[i]]-tab[y[i]-1];
            }
        }
    }
    int main()
    {
        n=read();q=read();
        for (long long i=1;i<=n;i++) {a[i]=read();s1[i]=s1[i-1]^a[i];s[i]=s1[i];}
        for (long long i=1;i<=q;i++) {x[i]=read();y[i]=read();k[i]=read();x[i]++;y[i]++;}
        calc(0,0);
        for (int i=1;i<=q;i++)
        {
            if (k[i])
            {
                long long l=y[i]-x[i]+2;
                ans[i]=(l/2+(l&1))*(l/2);
            }
        }
        for (long long i=1;i<=q;i++) printf("%lld
    ",ans[i]);
        return 0;
    }

    C.

      这TM的是个环套树啊。、

          我们找出路径上的值,然后每次加gcd(环长,m)加到最大即可。

          之前10分的原因是神TM没开long long。(我就说我怎么可能写挂这种题)(撤回)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxv 100500
    #define maxe 200500
    using namespace std;
    struct edge
    {
        long long v,w,nxt;
    }e[maxe];
    long long n,g[maxv],nume=1,dis1[maxv],dis2[maxv],root,father[maxv],anc[maxv][20],dep[maxv];
    long long r1,r2,q,s,t,m,u,v,w,a,b,x;
    long long read()
    {
        char ch;long long data=0;
        while (ch<'0' || ch>'9') ch=getchar();
        while (ch>='0' && ch<='9')
        {
            data=data*10+ch-'0';
            ch=getchar();
        }
        return data;
    }
    void addedge(long long u,long long v,long long w) {e[++nume].v=v;e[nume].w=w;e[nume].nxt=g[u];g[u]=nume;}
    long long getfather(long long x)
    {
        if (x!=father[x]) father[x]=getfather(father[x]);
        return father[x];
    }
    bool unionn(long long a,long long b)
    {
        long long f1=getfather(a),f2=getfather(b);
        if (f1==f2) return true;
        father[f1]=f2;return false;
    }
    void dfs(long long x,long long father)
    {
        for (long long i=g[x];i;i=e[i].nxt)
        {
            long long v=e[i].v;
            if (v!=father)
            {
                anc[v][0]=x;dep[v]=dep[x]+1;
                dis1[v]=dis1[x]+e[i].w;dis2[v]=dis2[x]+e[i^1].w;
                dfs(v,x);
            }
        }
    }
    void get_table()
    {
        for (long long e=1;e<=19;e++)
            for (long long i=1;i<=n;i++)
                anc[i][e]=anc[anc[i][e-1]][e-1];
    }
    long long lca(long long x,long long y)
    {
        if (dep[x]<dep[y]) swap(x,y);
        for (long long e=19;e>=0;e--)
            if ((dep[anc[x][e]]>=dep[y]) && (anc[x][e]))
                x=anc[x][e];
        if (x==y) return x;
        for (long long e=19;e>=0;e--)
        {
            if (anc[x][e]!=anc[y][e])
            {
                x=anc[x][e];
                y=anc[y][e];
            }
        }
        return anc[x][0];
    }
    long long gcd(long long a,long long b)
    {
        if (!b) return a;
        return gcd(b,a%b);
    }
    long long calc(long long x)
    {
        x=(x%m+m)%m;
        long long f1=(r1%m+m)%m,d1=gcd(f1,m);
        return (m-1-x)/d1*d1+x;
    }
    int main()
    {
        n=read();
        for (long long i=1;i<=n;i++) father[i]=i;
        for (long long i=1;i<=n;i++)
        {
            a=read();b=read();x=read();
            if (unionn(a,b)) {root=a;u=a;v=b;w=x;}
            else {addedge(a,b,x);addedge(b,a,-x);}
        }
        dfs(root,0);get_table();
        r1=dis1[v]-w;r2=dis2[v]+w;
        q=read();
        for (long long i=1;i<=q;i++)
        {
            s=read();t=read();m=read();x=lca(s,t);
            printf("%lld
    ",calc(dis2[s]-dis2[x]+dis1[t]-dis1[x]));
        } 
        return 0;
    }
  • 相关阅读:
    js 模拟表单提交下载文件
    vue 刷新子组件方法解决使用v-if闪屏问题
    Java15-Tomcat&Servlet&HTTP&Request&Response
    JAVA26-SpringBoot-在线教育项目01
    20 Vue-ajax
    19 Vue-JQuery
    18 Vue-Json
    Java 20-Mybatis学习
    17 Vue-ES6语法之Promise、VueX、网络请求封装
    16 Vue-cli脚手架介绍与使用
  • 原文地址:https://www.cnblogs.com/ziliuziliu/p/6196971.html
Copyright © 2020-2023  润新知