YNOI2016 这是我自己的发明

看到这个标题立刻想到:、

“绝地科学家,八倍不屏息啊,八百里外把头打啊...”

首先我们发现如果只考虑第二个操作,这棵树就是假的,我们可以直接莫队解决

如果考虑换根的话...可以把一个操作换成小于等于9个操作就可以了

当然怎么换,有一些非常恶心的分类讨论

嘤嘤嘤

YNOI 题是好题 但是要卡常 首先要fread & fwrite

然后需要wxh的莫队写法

然后要算一下分块大小

sqrt(q_size) -> (n / sqrt(q_size))

40 -> 100

嘤嘤嘤

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline char nc()
{
    static char buf[100000] , *p1 , *p2;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
    int ret = 0; char ch = nc();
    while(!isdigit(ch)) ch = nc();
    while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc();
    return ret;
}
char pbuf[100000] , *pp = pbuf;
inline void push(const char ch)
{
    if(pp == pbuf + 100000) fwrite(pbuf , 1 , 100000 , stdout) , pp = pbuf;
    *pp ++ = ch;
}
inline void write(long long x)
{
    static char sta[20];
    int top = 0;
    if(!x) push('0');
    while(x) sta[++top] = x % 10 ^ '0' , x /= 10;
    while(top) push(sta[top -- ]);
    push('\n');
}
const int maxn = 100010;
int n,m,rt;
int qx;
int a[maxn],vi[maxn];
int q_size;
int first[maxn],to[maxn << 1],nx[maxn << 1],cnt;
inline void add(int u,int v)
{
    to[++cnt] = v;
    nx[cnt] = first[u];
    first[u] = cnt;
}
inline void ins(int u,int v){add(u,v);add(v,u);}
struct Q
{
    int l,r,bl,id,opt;
    Q(){};
    Q(int _l,int _r,int _id,int _opt){l = min(_l,_r),r = max(_l,_r),id = _id,opt = _opt;}
    bool operator < (const Q &b)const
    {
        if(bl == b.bl)
        {
            if(bl & 1)
            return r < b.r;
            return r > b.r;
        }
        return l < b.l;
    }
}qs[maxn * 45];
int fa[maxn][23],dep[maxn],ind[maxn],oud[maxn],reh[maxn],dfn;
inline void dfs(int x)
{
    ind[x] = ++dfn;reh[dfn] = a[x];
    for(int i=1;i<=22;i++)
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for(int i=first[x];i;i=nx[i])
    {
        if(to[i] == fa[x][0])continue;
        dep[to[i]] = dep[x] + 1;
        fa[to[i]][0] = x;
        dfs(to[i]);
    }oud[x] = dfn;
}
LL ans[maxn * 5];
LL now;int cnt_x[maxn],cnt_y[maxn];
inline int go_anc(int x , int y)
{
    int i;
    for(i = 22 ; ~i ; i -- )
        if(dep[y] - dep[x] > (1 << i))
            y = fa[y][i];
    return y;
}
int xpos[10],ypos[10],opt_x[10],opt_y[10];
int main()
{
    freopen("1.in","r",stdin);
    freopen("www.out","w",stdout);
    int tx,ty;
    n = read(),m = read();
    for(int i=1;i<=n;i++)vi[i] = a[i] = read();
    sort(vi + 1,vi + n + 1);
    for(int i=1;i<=n;i++)a[i] = lower_bound(vi + 1,vi + n + 1,a[i]) - vi;
    for(int i=2;i<=n;i++)
    {
        int u = read(),v = read();
        ins(u,v);
    }dfs(rt = 1);
    //return 0;
    for(int i=1;i<=m;i++)
    {
        int t = read(),x = read();
        if(t == 1){rt = x;continue;}
        int y = read(),z;q_size++;
        tx = ty = 0;
        if(x == rt) xpos[++tx] = n , opt_x[tx] = 1;
        else if(ind[rt] < ind[x] || ind[rt] > oud[x]) xpos[++tx] = oud[x] , opt_x[tx] = 1 , xpos[++tx] = ind[x] - 1 , opt_x[tx] = -1;
        else z = go_anc(x , rt) , xpos[++tx] = n , opt_x[tx] = 1 , xpos[++tx] = oud[z] , opt_x[tx] = -1 , xpos[++tx] = ind[z] - 1 , opt_x[tx] = 1;
        
        if(y == rt) ypos[++ty] = n , opt_y[ty] = 1;
        else if(ind[rt] < ind[y] || ind[rt] > oud[y]) ypos[++ty] = oud[y] , opt_y[ty] = 1 , ypos[++ty] = ind[y] - 1 , opt_y[ty] = -1;
        else z = go_anc(y , rt) , ypos[++ty] = n , opt_y[ty] = 1 , ypos[++ty] = oud[z] , opt_y[ty] = -1 , ypos[++ty] = ind[z] - 1 , opt_y[ty] = 1;
        
        for(int j=1;j<=tx;j++)
            for(int k=1;k<=ty;k++)
                if(xpos[j] && ypos[k])
                    qs[++qx] = Q(xpos[j] , ypos[k] , q_size , opt_x[j] * opt_y[k]);
    }
    int si = (int)(n / sqrt(qx));
    for(int i=1;i<=qx;i++)qs[i].bl = (qs[i].l - 1) / si;
    sort(qs + 1,qs + qx + 1);
    int l = 0,r = 0;
    for(int i=1;i<=qx;i++)
    {
        while(l < qs[i].l){l++;now += cnt_y[reh[l]],cnt_x[reh[l]]++;}
        while(r < qs[i].r){r++;now += cnt_x[reh[r]],cnt_y[reh[r]]++;}
        while(l > qs[i].l){cnt_x[reh[l]]--;now -= cnt_y[reh[l]];l--;}
        while(r > qs[i].r){cnt_y[reh[r]]--;now -= cnt_x[reh[r]];r--;}
        ans[qs[i].id] += now * qs[i].opt;
    }
    for(int i=1;i<=q_size;i++)write(ans[i]);
    fwrite(pbuf , 1 , pp - pbuf , stdout);
}
View Code

 

转载于:https://www.cnblogs.com/Kong-Ruo/p/9806520.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值