zoukankan      html  css  js  c++  java
  • CF375D Tree and Queries 题解

    感觉CF的题目名都好朴素的样子

    你谷链接

    首先这题显然是个dsu on tree 但是我不会。
    其次这题显然是个莫队。这我会啊!
    然后会发现好像不是很对劲。因为每次询问都有一个k,貌似和传统的莫队数颜色有点不一样。
    本蒟蒻看到这里的时候内心是崩溃的。然后就看了一眼题解
    然后我就迷惑了。震惊,前缀和还可以O(1)修改,活到爆!
    然后经过郭神的一番论证以后,我惊讶的发现,这个题还真能O(1)修改前缀和。
    首先,两个数组。sum[i]表示出现次数大于i的颜色的数量。val[i]表示颜色i的出现次数。
    那么考虑莫队做法,当上一个询问的答案转移到当下的答案时,我们假设颜色i的数量要++。那么sum[val[i]+1]++;
    但是会发现,出现次数是(val[i]+1)的颜色数量+1,而对应的,出现次数是(val[i])的颜色数量就要-1。也就是说,每次对颜色的修改,只会涉及到sum数组的单点,而不会涉及到前缀(或后缀)。
    弄清楚这个,代码就很简单了。做个dfn序,跑普通莫队即可。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=100000+10;
    #define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
    #define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })
    char buf[1 << 20], *p1, *p2;
    struct node{
        int to,next;
    }edge[maxn<<1];
    int n,cnt,Time,m,ss;
    int size[maxn],head[maxn],dfn[maxn],a[maxn],w[maxn],belong[maxn],sum[maxn],res[maxn],val[maxn];
    struct Q{
        int l,r,data,k;
    }b[maxn];
    void add(int from,int to){
        edge[++cnt].to=to;
        edge[cnt].next=head[from];
        head[from]=cnt;
    }
    void dfs1(int u,int f){
        size[u]=1;
        dfn[u]=++Time;
        w[Time]=a[u];
        for(int i=head[u];i;i=edge[i].next){
            int v=edge[i].to;
            if(v==f) continue;
            dfs1(v,u);
            size[u]+=size[v];
        }
    }
    bool cmp(Q x,Q y){
        return belong[x.l]!=belong[y.l] ? x.l<y.l : belong[x.l]&1 ? x.r<y.r : x.r>y.r ;
    }
    void Solve(){
        n=read(); m=read();
        ss=sqrt(n);
        for(int i=1;i<=n;++i) a[i]=read();
        for(int i=1;i<=n;++i) belong[i]=(i-1)/ss+1;
        for(int i=1,x,y;i<n;++i) {
            x=read();
            y=read();
            add(x,y);
            add(y,x);
        }
        dfs1(1,0);
        for(int i=1,x;i<=m;++i){
            x=read();
            b[i].k=read();
            b[i].data=i;
            b[i].l=dfn[x];
            b[i].r=dfn[x]+size[x]-1;
        }
        sort(b+1,b+m+1,cmp);
        int l=1,r=0,ans=0;
        for(int i=1;i<=m;++i){
            while(l>b[i].l){
                --l;
                val[w[l]]++;
                sum[val[w[l]]]++;
            }
            while(r<b[i].r){
                ++r;
                val[w[r]]++;
                sum[val[w[r]]]++;
            }
            while(l<b[i].l){
                sum[val[w[l]]]--;
                val[w[l]]--;
                l++;
            }
            while(r>b[i].r){
                sum[val[w[r]]]--;
                val[w[r]]--;
                r--;
            }
            res[b[i].data]=sum[b[i].k];
        }
        for(int i=1;i<=m;++i) printf("%d
    ",res[i]);
    }
    int main(){
        Solve();
        return 0;
    }
    
  • 相关阅读:
    OC-内存管理-基本原理与引用计数器
    OC-改错题
    OC-Q&A
    OC-SEL
    CO-类的本质、description方法
    Tomcat 下 mysql的连接池配置和使用
    转:JAVA.NET.SOCKETEXCEPTION: TOO MANY OPEN FILES解决方法
    使应用程序常驻内存,不能被任务管理器关闭之配置文件设置
    解决Tomcat catalina.out 不断成长导致档案过大的问题
    >/dev/null 2>&1的含义
  • 原文地址:https://www.cnblogs.com/wwcdcpyscc/p/13832397.html
Copyright © 2011-2022 走看看