题面

题意:T组数据,每次给你1e5个点的树(1为根),每个点有一权值,询问1-n每个节点的子树中,

至少修改几个点的权值(每次都可以任意修改),才能让子树中任意2点的距离==他们权值差的绝对值

无解输出-1

题解:画图不难发现,如果这个节点有3个儿子,也就是不包含它连向它父亲的边,它还有多于2条边的话,一定不行

因为子节点权值只能是这个节点+1或者-1,所以只能存在最多2个

那我们就又发现了,只有这个子树,可以拉成一个链的时候,才有答案,

考虑在链中的情况,如何判断修改最少的个数,使得这是个差为1的等差数列

一个显然的做法,每个数减去i,比如1 4 3 5 6 3 7,每个数减去位置0 2 0 1 2 -3 0

众数是0,有3个,所以答案就是7-3==4,至少修改4个数

我们再考虑合并的情况,可以使用启发式合并,每次让儿子数少的并向多的

可是我们又发现,这个节点一旦是2棵子树合并过了,他这颗子树就废掉了,以后就不会再用了

因为这个链已经使用了,而继续传回去的点是这个父节点,它又不在链的两端,所以总的复杂度O(n)

多组数据的清空怕T,所以在使用后,马上进行了清空,代码有点冗余

 #include<bits/stdc++.h>
using namespace std;
#define N 100007
int n,v[N],siz[N],de[N],vis[N],T,u,w;
vector<int> g[N];
int now,cnt1[][N*],mx1[],cnt2[][N*],mx2[];
int nod[][N],tot[],ad[N*],mxx,ans[N];
bool dfs(int x,int dep)
{
vis[x]=;
siz[x]=;
de[x]=dep;
bool re=;
int cnt=;
for(int i=;i<g[x].size();i++)
if(!vis[g[x][i]])
{
if(cnt != )
{
now^=;
mx1[now]=mx2[now]=;
for(int j=;j<=tot[now];j++)
{
int xx=nod[now][j];
cnt1[now][v[xx]-de[xx]]=;
cnt2[now][v[xx]+de[xx]]=;
}
tot[now]=;
}
re&=dfs(g[x][i],dep+),siz[x]+=siz[g[x][i]];
cnt++;
}
if(!re || g[x].size()> || (x== && g[x].size()==))
{
ans[x]=-;
return ;
}
if(g[x].size()== || (x== && g[x].size()==))
{
int tmp = ;
mxx = ;
for(int i = ; i <= tot[now]; i++)
{
int xx = nod[now][i];
ad[v[xx] - tmp]++; mxx = max(mxx, ad[v[xx] - tmp]); tmp++;
}
ad[v[x] - tmp]++; mxx = max(mxx, ad[v[x] - tmp]); tmp++;
for(int i = tot[now ^ ]; i >= ; i--)
{
int xx = nod[now ^ ][i];
ad[v[xx] - tmp]++; mxx = max(mxx, ad[v[xx] - tmp]); tmp++;
}
ans[x] = siz[x] - mxx; tmp = ;
for(int i = ; i <= tot[now]; i++)
{
int xx = nod[now][i];
ad[v[xx] - tmp]--; tmp++;
}
ad[v[x] - tmp]--; tmp++;
for(int i = tot[now ^ ]; i >= ; i--)
{
int xx = nod[now ^ ][i];
ad[v[xx] - tmp]--; tmp++;
} tmp = ;
mxx = ;
for(int i = ; i <= tot[now]; i++)
{
int xx = nod[now][i];
ad[v[xx] + tmp]++; mxx = max(mxx, ad[v[xx] + tmp]); tmp++;
}
ad[v[x] + tmp]++; mxx = max(mxx, ad[v[x] + tmp]); tmp++;
for(int i = tot[now ^ ]; i >= ; i--)
{
int xx = nod[now ^ ][i];
ad[v[xx] + tmp]++; mxx = max(mxx, ad[v[xx] + tmp]); tmp++;
}
ans[x] = min(ans[x], siz[x] - mxx);
tmp = ;
for(int i = ; i <= tot[now]; i++)
{
int xx = nod[now][i];
ad[v[xx] + tmp]--; tmp++;
}
ad[v[x] + tmp]--; tmp++;
for(int i = tot[now ^ ]; i >= ; i--)
{
int xx=nod[now^][i];
ad[v[xx]+tmp]--;tmp++;
}
return ;
}
nod[now][++tot[now]]=x;
cnt1[now][v[x]-dep]++;
if(cnt1[now][v[x]-dep]>mx1[now]) mx1[now]=cnt1[now][v[x]-dep];
cnt2[now][v[x]+dep]++;
if(cnt2[now][v[x]+dep]>mx2[now]) mx2[now]=cnt2[now][v[x]+dep];
ans[x]=siz[x]-max(mx1[now], mx2[now]);
return ;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
now=;
mx1[now]=mx2[now]=;
for(int j=;j<=tot[now];j++)
{
int xx=nod[now][j];
cnt1[now][v[xx]-de[xx]]=;
cnt2[now][v[xx]+de[xx]]=;
}
tot[now]=;
now=;
mx1[now]=mx2[now]=;
for(int j=;j<=tot[now];j++)
{
int xx=nod[now][j];
cnt1[now][v[xx]-de[xx]]=;
cnt2[now][v[xx]+de[xx]]=;
}
tot[now] = ;
now = ;
for(int i=;i<=n;i++) vis[i]=,ans[i]=;
for(int i=;i<=n;i++) g[i].clear();
for(int i=;i<=n;i++) scanf("%d",&v[i]),v[i]+=;
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&w);
g[u].push_back(w);
g[w].push_back(u);
}
dfs(,);
for(int i = ; i <= n; i++) printf("%d ", ans[i]);
puts("");
}
}

不挤在一次dfs里好像就短多了

 #include<bits/stdc++.h>
#define lld long long
#define N 300007
using namespace std;
int T,n,nn,pn,u,w;
int v[N],dep[N],fa[N],dp[N],dq[N];
int ch[N],ok[N],p[N],ans[N],sz[N];
vector<int> g[N];
void DFS(int x)
{
for (auto e: g[x]) if (e!=fa[x]) DFS(e);
p[pn++]=x;
}
void work(int id)
{
int t;
for (int i=;i<pn;i++)
{
if (id==-) t=p[i];else t=id;
ans[t]=max(ans[t],++dq[v[p[i]]+i]);
ans[t]=max(ans[t],++dp[v[p[i]]-i]);
if (i && id==-) ans[p[i]]=max(ans[p[i]],ans[p[i-]]);
}
for (int i=;i<pn;i++)
{
dp[v[p[i]]-i]--;
dq[v[p[i]]+i]--;
}
}
void solve(int x)
{
pn=;
DFS(x);
work(-);
}
void solve2(int x)
{
pn=;
int tn=-;
for (auto e: g[x]) if (e!=fa[x])
{
DFS(e);
if (tn==-)
{
p[pn++]=x;
tn=pn;
}
}
reverse(p+tn,p+pn);
work(x);
}
void dfs(int x)
{
ok[x]=sz[x]=;
ch[x]=;
for (auto e:g[x]) if (e!=fa[x])
{
ch[x]++;
fa[e]=x;
dfs(e);
sz[x]+=sz[e];
ok[x]&=ok[e];
}
ok[x]&=ch[x]<=;
if (!ok[x])
{
for (auto e:g[x]) if (e!=fa[x] && ok[e]) solve(e);
if (ch[x]==)
{
int c=;
for (auto e:g[x]) if (e!=fa[x] && ok[e]) c++;
if (c==) solve2(x);
}
}
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
for (int i=;i<n;i++)
{
g[i].clear();
scanf("%d",&v[i]);
v[i]+=n;
ans[i]=-;
}
for (int i=;i<n;i++)
{
scanf("%d%d",&u,&w);
u--;w--;
g[u].emplace_back(w);
g[w].emplace_back(u);
}
fa[]=-;
dfs();
if (ok[]) solve();
for (int i=;i<n;i++) printf("%d ",ans[i]==-?-:sz[i]-ans[i]);
puts("");
}
}

Gym - 101972B Arabella Collegiate Programming Contest (2018) B. Updating the Tree 树DFS的更多相关文章

  1. ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2018) Syria, Lattakia, Tishreen University, April, 30, 2018

    ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2018) Syr ...

  2. German Collegiate Programming Contest 2018​ B. Battle Royale

    Battle Royale games are the current trend in video games and Gamers Concealed Punching Circles (GCPC ...

  3. German Collegiate Programming Contest 2018​ C. Coolest Ski Route

    John loves winter. Every skiing season he goes heli-skiing with his friends. To do so, they rent a h ...

  4. 边双连通缩点+树dp 2015 ACM Arabella Collegiate Programming Contest的Gym - 100676H

    http://codeforces.com/gym/100676/attachments 题目大意: 有n个城市,有m条路,每条路都有边长,如果某几个城市的路能组成一个环,那么在环中的这些城市就有传送 ...

  5. Gym - 101810H ACM International Collegiate Programming Contest (2018)

    bryce1010模板 http://codeforces.com/gym/101810 #include <bits/stdc++.h> using namespace std; #de ...

  6. Gym - 101810F ACM International Collegiate Programming Contest (2018)

    bryce1010模板 http://codeforces.com/gym/101810 #include<bits/stdc++.h> using namespace std; #def ...

  7. Gym - 101810E ACM International Collegiate Programming Contest (2018)

    bryce1010模板 http://codeforces.com/gym/101810 #include<bits/stdc++.h> using namespace std; #def ...

  8. Gym - 101810D ACM International Collegiate Programming Contest (2018)

    bryce1010模板 http://codeforces.com/gym/101810 #include <bits/stdc++.h> using namespace std; #de ...

  9. Gym - 101810C ACM International Collegiate Programming Contest (2018)

    bryce1010模板 http://codeforces.com/gym/101810 #include <bits/stdc++.h> using namespace std; #de ...

随机推荐

  1. 12Cookie、Session

    12Cookie.Session-2018/07/24 1.保存会话数据 cookie客户端技术,把每个用户的数据以cookie的形式写给用户各自的浏览器 HttpSession服务端技术,服务器运行 ...

  2. 字符串、散列--P1598 垂直柱状图

    题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过100个字符),然后用柱状图输出每个字符在输入文件中出现的次数.严格地按照输出样例来安排你的输出格式. 输入输出格式 输入格 ...

  3. Linux设置history命令显示行数以及时间

    Linux和unix上都提供了history命令,可以查询以前执行的命令历史记录但是,这个记录并不包含时间项目因此只能看到命令,但是不知道什么时间执行的如何让history记录时间呢? 解决方案 注意 ...

  4. xfce 设在分辨率1920 1080

    #自定义cvt 1920 1080 #查看系统显示器名称xrandr #设置分辨率xrandr --newmode "1920x1080_60.00" 173.00 1920 20 ...

  5. 2014年武汉的IT行情好像不太好(续):20个月过后,再看当时面试过的几个公司--武汉财富基石-崩盘,辣妈萌宝-创业失败,朋友公司转交他人管理

     2014年9月的时候,写过一篇面试的总结性质的文章,"2014年武汉的IT行情好像不太好". 原文地址:blog.csdn.net/fansunion/article/detai ...

  6. 调试LM1117电压转换芯片

    LM1117(不是LM117)电源芯片是低压差线性稳压器,简称LDO(low dropout regulator),是一种非隔离(输入输出电压的地是一个地)的电压转换芯片.因此,在使用的时候,尽量让输 ...

  7. Windows窗口创建的具体步骤

    /*实现窗口创建的六步骤:第一步:创建入口函数WinMain第二步:注册窗口类第三部:实现回调函数的功能第四步:显示窗口第五步:更新窗口第六步:消息循环*/ #include "stdafx ...

  8. java 项目连接MySQL数据库

    1.导入jar包 mysql-connector-java-5.1.35百度云链接如下: 链接:https://pan.baidu.com/s/1DPvIwU_An4MA3mU5bQa6VA 密码:5 ...

  9. noip模拟赛 dwarf tower

    [问题描述]Vasya在玩一个叫做"Dwarf Tower"的游戏,这个游戏中有n个不同的物品,它们的编号为1到n.现在Vasya想得到编号为1的物品.获得一个物品有两种方式:1. ...

  10. [bzoj1356]Rectangle[Baltic2009][几何常识乱搞]

    虽然说是几何常识乱搞,但是想不到啊.. 题意:n个点取4个组成矩形,使面积最大,求面积. n<=1500 题解: 1.对角线相等且相互交于中点的四边形是矩形. 2.矩形四点共圆. 所以$n^2$ ...