spoj-cot2(树上莫队)

题解:因为是树上查询,我们可以在树上做下分块然后莫队,至于怎么分看你的技巧,我是先去学了一下联盟王国的树上分块据说那个操作的分块查询一块是sq~3sq的时间复杂度而且还是比较正统,所以我选择用那个分块,然后接着r我怎么操作呢,我们按dfs序,你会很神奇的发现如果我r按dfs操作的话我这里的操作时间复杂度大约是O(2×siz*n),siz是块数,然后转移怎么转移呢?你可以多画几个树形图自己尝试多种情况找下规律,我这是是两者的最大公共祖先不操作,那么你最后转移过去的时候会发现查询的l,r的最大公共祖先是没有操作的,特判一下就好了

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define mes(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define dec(i,a,b) for(int i = b; i >= a; i--)
#define fi first
#define se second
#define ls rt<<1
#define rs rt<<1|1
#define lson ls,L,mid
#define rson rs,mid+1,R
#define lowbit(x) x&(-x)
typedef double db;
typedef long long int ll;
typedef pair pii;
typedef unsigned long long ull;
const ll inf = 0x3f3f3f3f;
const int mx = 1e5+5;
const int mod = 1e9+7;
const int x_move[] = {1,-1,0,0,1,1,-1,-1};
const int y_move[] = {0,0,1,-1,1,-1,1,-1};
int n,m;
int fa[mx][20];
int    belong[mx];
int dep[mx];
int pos[mx];
int cnt[mx];
int st[mx];
int x[mx];
int a[mx];
int sz[mx];
int vis[mx];
int ans[mx];
int id,sq,top;
int siz;
int sum;
vectorg[mx];
struct node{
    int l,r;
    int id;
    int belong;
    bool operator<(const node &a)const{
        if(a.belong!=belong) return belong < a.belong;
        return pos[r] < pos[a.r];
    }
}s[mx];
void dfs(int u,int pre){
    pos[u] = ++id;
    fa[u][0] = pre;
    dep[u] = dep[pre]+1;
    st[++top] = u;
    for(int i = 0; i < g[u].size(); i++){
        int v = g[u][i];
        if(v==pre)continue;
        dfs(v,u);
        sz[u] += sz[v];
        if(sz[u]>=sq){
            sz[u] = 0;
            ++siz;
            while(st[top]!=u) belong[st[top--]] = siz;
        }
    }
    sz[u]++;
}
void calc(int u){
    if(cnt[a[u]]==1&&vis[u]==-1)
        sum--;
    if(cnt[a[u]]==0&&vis[u]==1)
        sum++;
    cnt[a[u]] += vis[u];
    vis[u] *= -1;
}
void update(int u,int v){
    while(u!=v){
        if(dep[u]<=dep[v]){
            calc(v);
            v = fa[v][0];
        }
        else{
            calc(u);
            u = fa[u][0];
        }
    }
}
void init(){
    for(int i = 1; i < 20; i++)
        for(int j = 1; j <= n; j++)
            fa[j][i] = fa[fa[j][i-1]][i-1];
}
int lca(int u,int v){
    if(dep[u]= 0; i--)
        if(dep[fa[u][i]]>=dep[v]) u = fa[u][i];
    if(u==v)    return u;
    for(int i = 19; i >= 0; i--)
        if(fa[u][i]!=fa[v][i])    u = fa[u][i],v = fa[v][i];
    return fa[u][0];
}
int main(){
    //freopen("test.in","r",stdin);
    //freopen("test.out","w",stdout);
    int t,q,ca = 1;    
    scanf("%d%d",&n,&q);
    for(int i = 1; i <= n; i++)
        scanf("%d",&a[i]),x[i] = a[i],vis[i] = 1;
    sort(x+1,x+n+1);
    for(int i = 1; i <= n; i++)
        a[i] = lower_bound(x+1,x+n+1,a[i])-x;
    for(int i = 2; i <= n; i++){
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    sq = sqrt(n);
    dfs(1,0);
    siz++;
    while(top>0) belong[st[top--]] = siz;
    for(int i = 1; i <= q; i++){
        scanf("%d%d",&s[i].l,&s[i].r);
        s[i].id = i;
        s[i].belong = belong[s[i].l];
    }
    init();
    sort(s+1,s+q+1);
    update(s[1].l,s[1].r);
    int l = s[1].l,r = s[1].r;
    ans[s[1].id] = sum + (cnt[a[lca(l,r)]]==0);
    for(int i = 2; i <= q; i++){
        update(l,s[i].l);
        update(r,s[i].r);
        l = s[i].l;
        r = s[i].r;
        ans[s[i].id] = sum+(cnt[a[lca(l,r)]]==0);
    }
    for(int i = 1; i <= q; i++)
        printf("%d\n",ans[i]);
    return 0;
}

 

你可能感兴趣的:(莫队)