Codechef 13.11MONOPLOY LCT+树链剖分+线段树
题解:
我分到的集训队作业的A,傻逼数据结构题。
注意到每次操作就是将这个点Access一下,同时这个点需要跨越的国家数就是走过的虚边数。
那么考虑子树内部所有点走过虚边数目之和。
子树内的每条虚边,不妨设为i的父亲边,会产生$siz_i$的贡献。
假设询问的是x,求出子树内所有虚边的贡献,求完平均值之后再加上x到根的路径上有多少虚边就行了。
每次Access的时候用树链剖分维护实虚边的切换。
时间复杂度$O(nlog^2n)$。
代码:
目前在CC上rank1,然并卵。
#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int getc(){
static const int L=1<<15;
static char buf[L],*S=buf,*T=buf;
if(S==T){
T=(S=buf)+fread(buf,1,L,stdin);
if(S==T)
return EOF;
}
return*S++;
}
int getint(){
int c;
while(!isdigit(c=getc()));
int x=c-'0';
while(isdigit(c=getc()))
x=(x<<1)+(x<<3)+c-'0';
return x+1;
}
char getch(){
char c;
while((c=getc())!='O'&&c!='q');
return c;
}
#define N 100010
int head[N],next[N<<1],end[N<<1],ind;
void addedge(int a,int b){
int q=++ind;
end[q]=b;
next[q]=head[a];
head[a]=q++;
}
void make(int a,int b){
addedge(a,b);
addedge(b,a);
}
int siz[N],son[N],pa[N],dep[N];
void dfs1(int x,int fa){
siz[x]=1;
int mx=-1;
for(int j=head[x];j;j=next[j])
if(end[j]!=fa){
dep[end[j]]=dep[x]+1;
pa[end[j]]=x;
dfs1(end[j],x);
siz[x]+=siz[end[j]];
if(siz[end[j]]>mx){
mx=siz[end[j]];
son[x]=end[j];
}
}
}
int p_id[N],id_p[N],top[N],id;
void dfs2(int x,int Top){
top[x]=Top;
p_id[x]=++id;
id_p[id]=x;
if(son[x])
dfs2(son[x],Top);
for(int j=head[x];j;j=next[j])
if(end[j]!=pa[x]&&end[j]!=son[x])
dfs2(end[j],end[j]);
}
struct SegmentTree{
ll a[262144],b[262144],M;
void init(int _siz){
for(M=1;M<(_siz+2);M<<=1);
for(int i=1;i<(M<<1);++i)
a[i]=b[i]=0;
for(int i=2;i<=_siz;++i){
a[M+i]=1;
b[M+i]=siz[id_p[i]];
}
for(int i=M-1;i>=1;--i){
a[i]=a[i<<1]+a[i<<1^1];
b[i]=b[i<<1]+b[i<<1^1];
}
}
ll qa(int tl,int tr){
if(tl>tr)
return 0;
ll re=0;
for(tl+=M-1,tr+=M+1;tl^tr^1;tl>>=1,tr>>=1){
if(~tl&1)
re+=a[tl^1];
if(tr&1)
re+=a[tr^1];
}
return re;
}
ll qb(int tl,int tr){
if(tl>tr)
return 0;
ll re=0;
for(tl+=M-1,tr+=M+1;tl^tr^1;tl>>=1,tr>>=1){
if(~tl&1)
re+=b[tl^1];
if(tr&1)
re+=b[tr^1];
}
return re;
}
void ma(int x,int v){
for(a[x+=M]=v,x>>=1;x;x>>=1)
a[x]=a[x<<1]+a[x<<1^1];
}
void mb(int x,int v){
for(b[x+=M]=v,x>>=1;x;x>>=1)
b[x]=b[x<<1]+b[x<<1^1];
}
}Seg;
#define ls ch[0]
#define rs ch[1]
#define inf 0x3f3f3f3f
typedef pair<int,int> pii;
#define mp make_pair
struct Node{
Node*ch[2],*pa;
pii mn;
int id;
Node():mn(mp(inf,inf)),id(inf){}
bool d(){
return this==pa->rs;
}
void sc(Node*p,bool d){
ch[d]=p;
p->pa=this;
}
void up();
bool isroot();
}mem[N],*P,Tnull,*null=&Tnull,*ins[N];
Node*newnode(){
++P;
P->ls=P->rs=P->pa=null;
P->id=P-mem;
P->mn=mp(dep[P->id],P->id);
return P;
}
void Node::up(){
mn=mp(dep[id],id);
if(ls!=null)
mn=min(mn,ls->mn);
if(rs!=null)
mn=min(mn,rs->mn);
}
bool Node::isroot(){
return pa==null||(this!=pa->ls&&this!=pa->rs);
}
void Rot(Node*p){
bool d=p->d();
Node*fa=p->pa;
fa->sc(p->ch[!d],d);
fa->up();
p->pa=fa->pa;
if(!fa->isroot())
fa->pa->ch[fa->d()]=p;
p->sc(fa,!d);
}
void Splay(Node*p){
while(!p->isroot()){
if(p->pa->isroot())
Rot(p);
else
Rot(p->d()==p->pa->d()?p->pa:p),Rot(p);
}
p->up();
}
void Access(Node*p){
Node*q=null;
while(p!=null){
Splay(p);
if(p->rs!=null){
Seg.ma(p_id[p->rs->mn.second],1);
Seg.mb(p_id[p->rs->mn.second],siz[p->rs->mn.second]);
}
if(q!=null){
Seg.ma(p_id[q->mn.second],0);
Seg.mb(p_id[q->mn.second],0);
}
p->sc(q,1);
p->up();
q=p;
p=p->pa;
}
}
void reset(){
ind=0;
memset(head,0,sizeof head);
memset(son,0,sizeof son);
id=0;
P=mem;
}
int query(int x){
int re=0;
while(top[x]!=1){
re+=Seg.qa(p_id[top[x]],p_id[x]);
x=pa[top[x]];
}
return re+Seg.qa(p_id[1],p_id[x]);
}
int main(){
//#ifndef ONLINE_JUDGE
// freopen("tt.in","r",stdin);
//#endif
int T=getint()-1,n,a,b,i,j,q,x;
char ch;
while(T--){
reset();
n=getint()-1;
for(i=1;i<n;++i){
a=getint();
b=getint();
make(a,b);
}
dep[1]=1;
dfs1(1,-1);
dfs2(1,1);
for(i=1;i<=n;++i)
ins[i]=newnode();
for(i=2;i<=n;++i)
ins[i]->pa=ins[pa[i]];
Seg.init(n);
for(q=getint()-1;q;q--){
ch=getch();
if(ch=='O')
Access(mem+getint());
else{
x=getint();
printf("%.10lf\n",((double)Seg.qb(p_id[x]+1,p_id[x]+siz[x]-1)/siz[x])+query(x));
}
}
}
return 0;
}
Sep 23, 2015 05:55:31 PM
求开大时限!求不卡常数!