spoj-cot2(树上莫队)

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

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<cstdlib>
#include<ctime>
#include<stack>
#include<bitset>
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<int,int> 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;
vector<int>g[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]<dep[v])
        swap(u,v);
    for(int i = 19; i >= 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;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值