幻想乡战略游戏
Description
傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点u上,并且空地v上有dv个单位的军队,那么幽香每天就要花费dv×dist(u,v)的金钱来补给这些军队。由于幽香需要补给所有的军队,因此幽香总共就要花费为Sigma(Dv*dist(u,v),其中1<=V<=N)的代价。其中dist(u,v)表示u个v在树上的距离(唯一路径的权和)。 因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。
Input
第一行两个数n和Q分别表示树的点数和幽香操作的个数,其中点从1到n标号。
接下来n-1行,每行三个正整数a,b,c,表示a和b之间有一条边权为c的边。
接下来Q行,每行两个数u,e,表示幽香在点u上放了e单位个军队
(如果e<0,就相当于是幽香在u上减少了|e|单位个军队,说白了就是du←du+e)。
数据保证任何时刻每个点上的军队数量都是非负的。
1<=c<=1000, 0<=|e|<=1000, n<=10^5, Q<=10^5
对于所有数据,这个树上所有点的度数都不超过20
N,Q>=1
Output
对于幽香的每个操作,输出操作完成以后,每天的最小花费,也即如果幽香选择最优的补给点进行补给时的花费。
Sample Input
10 5
1 2 1
2 3 1
2 4 1
1 5 1
2 6 1
2 7 1
5 8 1
7 9 1
1 10 1
3 1
2 1
8 1
3 1
4 1
Sample Output
0
1
4
5
6
样例有误,输入边的地方有两行边权和点的编号中间没加空格……
话说一遍过还真是舒服啊
难道咱有写工业题的潜质?
(今早NOIP模拟题T1誓死不用STL写出280+行,STL党仅需120+行(虽然还是A了))
思路:
如果可以动态维护每个点的答案值,那么就可以很稳地做出此题。
可以发现,如果咱记录点u的子树点权和sumd[u],那么如果u到当前要计算值的点需要经过其父亲边向父亲走,那么这条父亲边对答案的贡献便是其权值*sumd[u]。
那么考虑维护sumd[u]来求答案。
考虑到出题人必须要足够坑的基本素质,每次如果暴力修改,复杂度会是是O(n)的,单次询问由于需要计算经过的点,复杂度也是O(n)的。
那这就会很尴尬地TLE了……
考虑使用动态点分治优化树的结构——建出树高仅为log的点分树。
所谓点分树,就是在点分治时把各个分治中心连在一起得到的一棵树~
那么可以发现之前的式子无法直接使用边权,而且还需要减去与父亲节点之间相冲突的子树部分。
那就维护一个dis,代表以u为根的子树中,所有节点到u的父亲所需的价值和,再维护一个fadis,代表以u为根的子树中,所有节点到u所需的价值和。
(名字很奇怪对吧只是咱写代码时写反了而已)
这两个值可以在修改操作时维护一下。
那么这就可以用加减法排除掉重复子树的影响了~~
修改直接暴力从被修改点开始往上一个个暴力跳父亲,反正点分树深度log~
至于查询,可以发现(显然是错的,显然可以随手卡掉)新的答案位置在原树上不会距离上一个答案位置太远。
那就在原树上暴力跳可好??反正单点价值查询只是log~~
(10s时限只用了4s证明效果还是不错的)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N=1e5+9;
const ll K=22;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0' || '9'<ch){if(ch=='-')f=-1;ch=getchar();}
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x*f;
}
inline void chkmax(ll &a,ll b){if(a<b)a=b;}
inline ll minn(ll a,ll b){if(a<b)return a;return b;}
ll n,q,lans=1;
ll d[N];
namespace tree
{
ll to[N<<1],nxt[N<<1],w[N<<1],beg[N],tot=1;
ll id[N],dfn,st[N<<1][K],dep[N],logs[N<<1];
ll fa[N],sumd[N],dis[N],fadis[N];
bool ban[N<<1];
inline void add(int u,int v,int c)
{
to[++tot]=v;
nxt[tot]=beg[u];
w[tot]=c;
beg[u]=tot;
}
inline void dfs(ll u,ll fat=0)
{
st[++dfn][0]=dep[u];
id[u]=dfn;
for(ll i=beg[u],v;i;i=nxt[i])
if((v=to[i])!=fat)
{
dep[v]=dep[u]+w[i];
dfs(v,u);
st[++dfn][0]=dep[u];
}
}
inline void init()
{
for(ll i=2;i<=dfn;i++)
logs[i]=logs[i>>1]+1;
for(ll i=1;i<=logs[dfn];i++)
for(ll j=1;j+(1<<i)-1<=dfn;j++)
st[j][i]=minn(st[j][i-1],st[j+(1<<i-1)][i-1]);
}
inline ll dist(ll u,ll v)
{
ll ret=dep[u]+dep[v];
u=id[u],v=id[v];
if(u>v)swap(u,v);
ll dis=logs[v-u+1];
return ret-2*minn(st[u][dis],st[v-(1<<dis)+1][dis]);
}
inline ll get_siz(ll u,ll fa=0)
{
ll siz=1;
for(ll i=beg[u];i;i=nxt[i])
if(!ban[i] && to[i]!=fa)
siz+=get_siz(to[i],u);
return siz;
}
inline ll get_center(ll u,ll fa,ll totsiz,ll &root)
{
ll mxsiz=0,siz=1;
for(ll i=beg[u],v,tmp;i;i=nxt[i])
if(!ban[i] && (v=to[i])!=fa)
{
siz+=(tmp=get_center(v,u,totsiz,root));
chkmax(mxsiz,tmp);
}
chkmax(mxsiz,totsiz-siz);
if((mxsiz<<1)<=totsiz)
root=u;
return siz;
}
inline ll solve(ll u)
{
ll totsiz=get_siz(u),root;
get_center(u,0,totsiz,root);
sumd[root]=d[root];
for(ll i=beg[root],son;i;i=nxt[i])
if(!ban[i])
{
ban[i]=ban[i^1]=1;
son=solve(to[i]);
fa[son]=root;
sumd[root]+=sumd[son];
}
return root;
}
inline void update(ll u,ll val)
{
sumd[u]+=val;
for(ll i=u;fa[i];i=fa[i])
{
ll diss=dist(fa[i],u);
sumd[fa[i]]+=val;
dis[i]+=val*diss;
fadis[fa[i]]+=val*diss;
}
}
inline ll calc(ll u)
{
ll ret=fadis[u];
for(ll i=u;fa[i];i=fa[i])
{
ret+=(fadis[fa[i]]-dis[i]);
ret+=dist(fa[i],u)*(sumd[fa[i]]-sumd[i]);
}
return ret;
}
inline ll query(ll u)//no fa anymore
{
ll ret=calc(u);
for(ll i=beg[u],v;i;i=nxt[i])
if(calc(v=to[i])<ret)
return query(v);
lans=u;
return ret;
}
}
using namespace tree;
int main()
{
if(fopen("tree.in","r"))
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
}
n=read();
q=read();
for(ll i=1,u,v,c;i<n;i++)
{
u=read();
v=read();
c=read();
add(u,v,c);
add(v,u,c);
}
dfs(1);
init();
solve(1);
for(ll i=1,u,e;i<=q;i++)
{
u=read();
e=read();
update(u,e);
printf("%lld\n",query(lans));
}
return 0;
}