题目大意:给定一棵树,初始每个点都有一个颜色,支持三种操作:
1.将某个点到根的路径上所有点染上一种新的颜色
2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点
3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值
答什么答,抄别人模板还好意思BB
bzoj3779
隐藏题
我这么说你们可能不懂,看代码!!!
1.线段树
2.LCT
3.dfs序
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1e5 + 6;
const int Nlg = 18;
int n, m;//n,m见题
int to[N+N], next[N+N], end[N], tms;//4个是前向星
int fi[N], se[N], rat[N], dep[N], fa[N], up[N][Nlg];// fi:子树中最小dfs序值, se:子树中最大dfs序值
//rat : dfs序值对应的树上编号 dep :深度 fa :父节点 up:LCA
namespace seg//线段树部分
{
LL cnt[N<<2];
int tag[N<<2], siz[N<<2];
void pup(int x){cnt[x] = cnt[x+x] + cnt[x+x+1];}
void ptg(int x, int tg){tag[x] += tg, cnt[x] += siz[x] * tg;}
void pdw(int x){if(tag[x]) ptg(x+x, tag[x]), ptg(x+x+1, tag[x]), tag[x]=0;}
void cons(int x, int l, int r)
{
cnt[x] = tag[x] = 0, siz[x] = r-l+1;
if(l==r) {cnt[x] = dep[rat[l]]; return;}
int mid = (l+r) >> 1;
cons(x+x, l, mid), cons(x+x+1, mid+1, r);
pup(x);
}
int opl, opr, opty, opg;
LL opans;
// 0 : modify 1 : query
void step(int x, int l, int r)
{
if(opl<=l && r<=opr)
{
if(opty) opans += cnt[x]; else ptg(x, opg);
return;
}
int mid = (l+r)>>1; pdw(x);
if(opl<=mid) step(x+x, l, mid);
if(opr>mid) step(x+x+1, mid+1, r);
if(!opty) pup(x);
}
int root;
int ances(int x, int y){ return fi[x] <= fi[y] && fi[y] <= se[x]; }
int jump(int x, int h) { for(int i=0; h; h>>=1, i++) if(h&1) x=up[x][i]; return x;}
void deal(int x)
{
if(x == root) opl = 1, opr = n, step(1, 1, n);
else if(ances(x, root))
{
x = jump(root, dep[root]-dep[x]-1);
if(fi[x]>1) opl = 1, opr = fi[x]-1, step(1, 1, n);
if(se[x]1, opr = n, step(1, 1, n);
}
else opl = fi[x], opr = se[x], step(1, 1, n);
}
void modify(int x, int op) { opty = 0, opg = op, deal(x); }
LL query(int x) { return opty = 1, opans = 0, deal(x), opans; }
int count(int x)
{
if(x == root) return n;
if(ances(x, root)) return x = jump(root, dep[root]-dep[x]-1), n-(se[x]-fi[x]+1);
return se[x]-fi[x]+1;
}
}
namespace lct
{
struct rc
{
int rev, l, r, val;
rc *c[2], *f;
int d(){return f->c[1]==this;}
int rt(){return f->c[1]!=this && f->c[0]!=this;}
void sc(rc *x, int d){c[d]=x, x->f=this;}
void pup(){l = c[0]->val ? c[0]->l : val, r = c[1]->val ? c[1]->r : val;}
void re(){rev^=1, swap(c[0], c[1]), swap(l, r);}
void pdw(){if(rev) c[0]->re(), c[1]->re(), rev=0;}
}nil[N];
#define T(x) (nil+x)
void zig(rc *x)
{
int d = x->d();
rc *p = x->f;
p->sc(x->c[!d], d), p->pup();
if(p->rt()) x->f=p->f; else p->f->sc(x, p->d());
x->sc(p, !d);
}
void splay(rc *x)
{
for(rc *y; !x->rt(); )
{
if(y=x->f, !y->rt()) y->f->pdw();
y->pdw(), x->pdw();
if(!y->rt()) x->d() ^ y->d() ? zig(x) : zig(y);
zig(x);
}
x->pup();
}
void access(rc *x)
{
rc *v = x, *y = nil;
for(int u; x!=nil; )
{
splay(x), x->pdw();
if(x->c[1]!=nil) u=x->c[1]->l, seg :: modify(u, 1);
if(y!=nil) u=y->l, seg :: modify(u, -1);
x->sc(y, 1), x->pup(), y = x, x = x->f;
}
splay(v);
}
void evert(rc *x){access(x), x->re();}
void cons()//找根
{
for(int i=1; i<=n; i++)
T(i)->f = T(fa[i]), T(i)->l = T(i)->r = T(i)->val = i,
T(i)->c[0] = T(i)->c[1] = nil;
}
void upload(int x){ access(T(x)); }
void croot(int x){ evert(T(x)); }
}
namespace rec
{
//No.1 前向星存
void init()
{
scanf("%d%d", &n, &m);
for(int i=1, x, y; iscanf("%d%d", &x, &y);
to[++tms]=y, next[tms]=end[x], end[x]=tms;
to[++tms]=x, next[tms]=end[y], end[y]=tms;
}
}
//No.2 dfs
void dfs(int x)
{
fi[x] = ++fi[0], rat[fi[0]] = x, up[x][0] = fa[x];
for(int i=0; up[up[x][i]][i]; ++i) up[x][i+1] = up[up[x][i]][i];
for(int p=end[x], v; p; p=next[p]) if(v=to[p], v!=fa[x])
fa[v]=x, dep[v]=dep[x]+1, dfs(v);
se[x] = fi[0];
}
//No.3 建树
void prep()
{
dep[1] = 1, dfs(1);
seg :: cons(1, 1, n);
seg :: root = 1;
}
//No.4 输出
void answ()
{
for(int i=1, t, x; i<=m; i++)
{
scanf("%d%d", &t, &x);
if(t==1) lct :: upload(x);
else if(t==2) lct :: croot(x), seg :: root = x;
else printf("%.12lf\n", seg :: query(x) / double(seg :: count(x)));
}
}
}
int main()//这个main是不是很良心哇
{
rec :: init();
rec :: prep();
lct :: cons();
rec :: answ();
return 0;
}
如果你解决本题有什么人生经验(程序错误,我的错误,不懂的地方,奇奇怪怪的优化想法)可以留言偶!,我会选一些挂上。