zoukankan      html  css  js  c++  java
  • SPOJ COT2 Count on a tree II [树上莫队]

    题意:

    询问路径上多少种不同的点权


    我一直写了假的莫队!!!!

    正确的排序方式是$(pos[u],dfn[v])$,我却一直用原始点的编号排序!!!

    然后你会发现代码中有一些卡常...

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=2e5+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,Q,a[N],mp[N],u,v;
    struct edge{int v,ne;} e[N<<1];
    int cnt,h[N];
    inline void ins(int u,int v){
        e[++cnt]=(edge){v,h[u]}; h[u]=cnt;
        e[++cnt]=(edge){u,h[v]}; h[v]=cnt;
    }
    int block, pos[N], m, st[N], top;
    int fa[N][18], deep[N], dfn[N], dfc;
    void dfs(int u){
        dfn[u]=++dfc;
        for(int i=1; (1<<i)<=deep[u]; i++)
            fa[u][i]=fa[ fa[u][i-1] ][i-1];
        int bot=top;
        for(int i=h[u];i;i=e[i].ne) if(e[i].v!=fa[u][0]){
            fa[e[i].v][0]=u; deep[e[i].v]=deep[u]+1;
            dfs(e[i].v);
            if(top-bot>=block){
                m++;
                while(top!=bot) pos[st[top--]]=m;
            }
        }
        st[++top]=u;
    }
    inline int lca(int x,int y){
        if(deep[x]<deep[y]) swap(x, y);
        int bin=deep[x]-deep[y];
        for(int i=0;i<17;i++) if((1<<i)&bin) x=fa[x][i];
        if(x==y) return x;
        for(int i=16;i>=0;i--) 
            if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
        return x==y ? x : fa[x][0];
    }
    
    struct meow{
        int u, v, id;
        bool operator <(const meow &a) const {return pos[u]==pos[a.u] ? dfn[v]<dfn[a.v] : pos[u]<pos[a.u];}
    }q[N];
    
    int vis[N], cou[N], now, ans[N];
    inline void Xor(int u){
        if(!vis[u]) now+= (++cou[a[u]])==1;
        else now-= (--cou[a[u]])==0;
        vis[u]^=1;
    }
    inline void move(int x,int y){ //printf("%d --> %d  %d
    ",x,y,now);
        if(deep[x]<deep[y]) swap(x, y);
        while(deep[x]>deep[y]) Xor(x), x=fa[x][0];
        while(x!=y) Xor(x), Xor(y), x=fa[x][0], y=fa[y][0];
    }
    void modui(){
        u=1, v=1;
        for(int i=1;i<=Q;i++){
            if(u!=q[i].u) move(u, q[i].u), u=q[i].u;
            if(v!=q[i].v) move(v, q[i].v), v=q[i].v;
            int anc=lca(u, v);
            ans[q[i].id]= now + (cou[a[anc]]==0);
        }
    }
    int main(){
        freopen("in","r",stdin);
        n=read(); Q=read();
        for(int i=1;i<=n;i++) a[i]=mp[i]=read();
        sort(mp+1, mp+1+n); mp[0]=unique(mp+1, mp+1+n)-mp-1;
        for(int i=1;i<=n;i++) a[i]=lower_bound(mp+1, mp+1+mp[0], a[i])-mp;
        for(int i=1;i<n ;i++) ins(read(), read() );
        block= sqrt(n);
        dfs(1);
        while(top) pos[st[top--]]=m;
        for(int i=1;i<=Q;i++){
            u=read(), v=read(); if(pos[u]>pos[v]) swap(u, v);
            q[i]=(meow){u, v, i};
        }
        sort(q+1, q+1+Q);
        modui();
        for(int i=1;i<=Q;i++) printf("%d
    ",ans[i]);
    }
  • 相关阅读:
    Mysql密码操作
    最长公共子串(2017蓝桥杯省赛)
    一和零(leetcode)
    leetcode 235周赛
    袋子里最少数目的球(leetcode)
    第七周课后作业
    第四周jsp作业
    3.10
    3.4课堂练习
    DS博客作业05-查找批改
  • 原文地址:https://www.cnblogs.com/candy99/p/6574439.html
Copyright © 2011-2022 走看看