dfs序+分块求众数

铅导体

问题描述
何老板要求第三题要很简单,最好是铅导体的难度。
于是,nodgd把N个铅块用N−1根导线相连,就形成了一个铅导体。只要是在这个基础上出题,就符合何老板的要求。nodgd为了方便,就把其中的一个铅块固定在了墙上,其他铅块在导线的作用下自然下垂。每个铅块有个固定的纯度,若干个相同纯度的铅块可以聚变发电,发电的电压与铅块的数量成正比。每当nodgd需要电疗的时候,就在铅导体上选一个铅块,把它和挂在它下面的所有铅块都取下来,在这当中选一些纯度相同的铅块发电,发电之后将这些铅块挂回原来的位置。nodgd希望电疗的电压越高越好,在电压相同的情况下,nodgd又希望使用纯度更低的铅块。
但是ciocio经常来捣乱,他时不时的把整个铅导体取下来,重新选一个铅块固定到墙上,其他的铅块继续自然下垂。那么问题来了,nodgd每次都想享受最高电压的电疗,需要你大声喊出应该使用多少个纯度是多
少的铅块。

输入格式
输入文件C.in。
第一行四个整数N, A, Q, I,表示铅块的数量、铅块纯度的范围、操作的总次数、测试点编号。
铅块按1 ∼ N编号,一开始nodgd把编号为1的铅块固定在墙上。铅块的纯度是1 ∼ A之间的一个整
数。
接下来N − 1行,每行两个整数u, v,表示有一条导线连接。
接下来一行,N个整数,表示每个铅块的纯度。
接下来Q行,每行输入两个整数op, u。
若op = 1,表示ciocio把整个铅导体取下来,再把编号为u的铅块重新固定在墙上。
若op = 2,表示nodgd把编号为u的铅块以及挂在他下面的所有铅块暂时取下来,选出其中一些铅块进行聚变发电。如果要求该组测试点要求强制在线,设上一次输出的答案两个数分别为lasta和lastb,则u′ = (u+lasta×23 + lastb×233)%N + 1才是真正的节点编号。

输出格式
输出文件C.out。
每次op = 2的时候输出一行,两个整数,分别是使用铅块的纯度和数量。

样例输入
5 3 8 0
1 2
1 3
3 4
3 5
1 1 2 2 3
2 3
2 1
2 5
1 3
2 4
2 2
2 1
2 3

样例输出
2 2
1 2
3 1
2 1
1 1
1 2
1 2

数据范围
这里写图片描述

dfs序+分块求众数,很机智的一个做法将新编号对应的纯度数组复制一遍,处理根在子树内就会方便很多。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int base=500;
template <typename T>
inline void _read(T& x){
    char t=getchar();bool sign=true;
    while(t<'0'||t>'9'){if(t=='-')sign=false;t=getchar();}
    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
    if(!sign)x=-x;
}
int n,m,q,I,N,S;
int tot,e,root;
int lasta,lastb;
int vistime;
struct line{
    int from,to;
    line(){}
    line(int x,int y){from=x;to=y;}
};
line edge[200005];
int last[100005],_next[200005];
void add_edge(int x,int y){
    edge[++e]=line(x,y);
    _next[e]=last[x];
    last[x]=e;
}
int father[100005],dep[100005],p[100005][35],id[100005],R[100005],purity[100005],a[100005];
void dfs(int x,int fa){
    int i,j,k,v;
    id[x]=++vistime;
    dep[x]=dep[fa]+1;
    father[x]=fa;
    k=ceil(log(dep[x])/log(2));
    p[x][0]=fa;
    for(i=1;i<=k;i++)p[x][i]=p[p[x][i-1]][i-1];
    for(i=last[x];i;i=_next[i]){
        v=edge[i].to;
        if(v==fa)continue;
        dfs(v,x);
    }
    R[x]=vistime;
}

struct node{
    int Purity,sum;
    node(){}
    node(int x,int y){Purity=x;sum=y;}
};
node block[605][1005];
int cnt[100005];
int all[605][100005];
void divide(){
    int i,j,k,t1,t2;
    N=(n<<1);
    tot=(N-1)/base+1;
    for(i=1;i<=tot;i++){
        int pure=0,sum=0;
        for(j=i;j<=tot;j++){
            int lim=j*base;
            lim=min(lim,N);
            for(k=(j-1)*base+1;k<=lim;k++){
                t1=a[k];
                t2=++cnt[a[k]];
                if(t2>sum||(t2==sum&&a[k]<pure)){
                    sum=cnt[a[k]];
                    pure=a[k];
                }
            }
            block[i][j]=node(pure,sum);
            if(i==1){
                for(k=1;k<=m;k++){
                    all[j][k]=cnt[k];
                }
            }
        }
        for(j=1;j<=m;j++)cnt[j]=0;
    }
}
int go_up(int x,int step){
    int i;
    for(i=S;i>=0;i--){
        if(step&(1<<i))x=p[x][i];
    }
    return x;
}
void solve(int x){
    //cout<<"solve:"<<x<<endl; 
    int l,r,i,j,k;
    if(x==root){
        l=1;
        r=n;
    }
    else if(id[x]<=id[root]&&id[root]<=R[x]){
        //cout<<"case1"<<endl;
        int temp=go_up(root,dep[root]-dep[x]-1);
        l=R[temp]+1;
        r=id[temp]-1+n;
    }
    else {
        //cout<<"case2"<<endl;
        l=id[x];r=R[x];
    }
    int bl,br,tl,tr;
    bl=(l-2+base)/base+1;
    br=r/base;
    tl=(bl-1)*base+1;
    tr=br*base;
    //cout<<"l:"<<l<<"  r:"<<r<<endl;
    //cout<<"block("<<bl<<","<<br<<")"<<endl;
    //cout<<"work["<<l<<","<<r<<"]"<<endl;
    int pure,sum,t1,t2;
    if(bl>br){
        //cout<<"fuck"<<endl;
        pure=0;sum=0;
        for(i=l;i<=r;i++){
            t1=++cnt[a[i]];
            t2=a[i];
            if(t1>sum||(t1==sum&&t2<pure)){
                sum=t1;pure=t2;
            }
        }
        //cout<<"cnt[105]:"<<cnt[105]<<endl;
        for(i=l;i<=r;i++)cnt[a[i]]=0;
    }
    else {
        pure=block[bl][br].Purity;
        sum=block[bl][br].sum;
        for(i=l;i<tl;i++){
            t1=++cnt[a[i]]+all[br][a[i]]-all[bl-1][a[i]];
            t2=a[i];
            if(t1>sum||(t1==sum&&t2<pure)){
                sum=t1;pure=t2;
            }
        }
        for(i=tr+1;i<=r;i++){
            t1=++cnt[a[i]]+all[br][a[i]]-all[bl-1][a[i]];
            t2=a[i];
            if(t1>sum||(t1==sum&&t2<pure)){
                sum=t1;pure=t2;
            }
        }
        for(i=l;i<tl;i++)cnt[a[i]]=0;
        for(i=tr+1;i<=r;i++)cnt[a[i]]=0;
    }
    printf("%d %d\n",pure,sum);
    lasta=pure;
    lastb=sum;
}
int main(){
    freopen("C.in","r",stdin);
    freopen("C.out","w",stdout);
    int i,j,k;
    cin>>n>>m>>q>>I;
    S=ceil(log(n)/log(2));
    for(i=1;i<n;i++){
        int x,y;
        _read(x);_read(y);
        add_edge(x,y);
        add_edge(y,x);
    }
    dfs(1,0);
    /*cout<<"fa:"<<endl;
    for(i=1;i<=n;i++){
        cout<<"i:"<<i<<" "<<p[i][0]<<" "<<p[i][1]<<endl;
    }*/
    for(i=1;i<=n;i++){
        _read(purity[i]);
        a[id[i]]=purity[i];
    }
    for(i=1;i<=n;i++){
        a[i+n]=a[i];
    }
    divide();
    while(q--){
        int op,x;
        _read(op);_read(x);
        if(I%2==0)x=(x+lasta*23+lastb*233)%n+1;
        //cout<<"x:"<<x<<endl;
        if(op==1){
            root=x;
        }
        else {
            solve(x);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值