铅导体
问题描述
何老板要求第三题要很简单,最好是铅导体的难度。
于是,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);
}
}
}