您的位置:首页 > 其它

[BZOJ4515][SDOI2016] 游戏 - 树链剖分 - 半平面交 - 标记永久化

2016-08-08 17:55 375 查看

4515: [Sdoi2016]游戏

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 390  Solved: 177

[Submit][Status][Discuss]

Description

Alice 和 Bob 在玩一个游戏。
游戏在一棵有 n 个点的树上进行。最初,每个点上都只有一个数字,那个数字是 123456789123456789。
有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字。对于路径上的一个点 r,
若 r 与 s 的距离是 dis,那么 Alice 在点 r 上添加的数字是 a×dis+b。有时,Bob 会选择一条从 s 到 t 的路径。
他需要先从这条路径上选择一个点,再从那个点上选择一个数字。
Bob 选择的数字越小越好,但大量的数字让 Bob 眼花缭乱。Bob 需要你帮他找出他能够选择的最小的数字。

Input

第一行两个数字 n、m,表示树的点数和进行的操作数。
接下来 n−1 行,每行三个数字 u、v、w,表示树上有一条连接 u、v 的边,长度是 w。
接下来 m 行。每行第一个数字是 1 或 2。
若第一个数是 1,表示 Alice 进行操作,接下来四个数字 s、t、a、b。
若第一个数是 2,表示 Bob 进行操作,接下来四个数字 s、t。

Output

每当 Bob 进行操作,输出一行一个数,表示他能够选择的最小的数字

Sample Input

3 5

1 2 10

2 3 20

2 1 3

1 2 3 5 6

2 2 3

1 2 3 -5 -6

2 2 3

Sample Output

123456789123456789

6

-106

HINT

 n≤100000,m≤100000,∣a∣≤10000,0<=w,|b|<=10^9

Source

鸣谢Menci上传

[Submit][Status][Discuss]

HOME Back

한국어  中文  فارسی  English  ไทย 

    显然我们首先应该树链剖分一下,这样就能将每个操作1转化成在许多个区间上的操作。那么这些操作是什么呢?显然,我们只要以任意点为根,求出每个点到根的距离deep[],就可以将每个操作1在其路径上的一点q的操作转化成deep[q]*x+y。我们考虑求出每个操作1的起点u和终点v的lca--p,则u-->p上有x=-a,y=a*deep[fr]+b,p-->v上有x=a,y=a*(deep[fr]-2*deep[p])+b。这样我们就相当于在线段树上维护许多条线段在对应点的最小值。

    处理这个问题,只要标记永久化一下就可以了,对于线段树上每个点记录其左/右端点最小时所在的直线,这样更新不下放标记的时间复杂度是O(log n)的,而查询只需要查询整棵线段树所走路径范围内的最小值即可(同一条链上的深度deep显然递增),总时间复杂度O(n log^3 n),但由于常数极小就可以A了。

    zzt线段树写了一个if(l==r&&s==t)导致很惨很惨 =-= 果然还是太弱辣

/**************************************************************
Problem: 4515
User: whzzt
Language: C++
Result: Accepted
Time:13172 ms
Memory:29268 kb
****************************************************************/

#include"bits/stdc++.h"
typedef long long ll;
using namespace std;
const int N=100005,LG=20;
const ll inf=123456789123456789ll;
#define fge getchar()
template <class MyInt>
inline void read(MyInt&x){
x=0;int f=1;char ch=fge;
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=fge;}
while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=fge;
x=x*f;
}

struct Line {
ll a,b;
Line (ll _=0,ll __=0)
{ a=_; b=__;}
inline ll F(ll x){return a*x+b;}
} li[N*2];int cnt;

ll mn[4*N];int flag[4*N];
int n,m,h
,to[2*N],nxt[2*N],d[2*N],tmp;
int size
,fa
[LG],bel
,dfn
,tot;
ll deep
,va
,DEEP
;

int lca(int x,int y){
if(DEEP[x]<DEEP[y])swap(x,y);
int dx=DEEP[x],dy=DEEP[y],l=dx-dy;
for(int i=0;l;i++)if(l&(1<<i))x=fa[x][i],l^=(1<<i);
for(int i=17;x!=y&&i>=0;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return x==y?x:fa[x][0];
}//O(log n)

void dfs1(int x){
for(int i=1;fa[x][i-1];fa[x][i]=fa[fa[x][i-1]][i-1],i++);
for(int i=h[x];i;i=nxt[i]){
if(to[i]!=fa[x][0]){
DEEP[to[i]]=DEEP[x]+1;
deep[to[i]]=deep[x]+d[i];
fa[to[i]][0]=x;dfs1(to[i]);
size[x]+=size[to[i]];
}
}
size[x]++;
}//O(n)

void dfs2(int x,int b){
int go=-1,siz=0,i;
bel[x]=b;dfn[x]=++tot;va[dfn[x]]=deep[x];
for(i=h[x];i;i=nxt[i])
if(to[i]!=fa[x][0]&&size[to[i]]>siz)
go=to[i],siz=size[to[i]];
if(go==-1)return;dfs2(go,b);
for(i=h[x];i;i=nxt[i])
if(to[i]!=go&&to[i]!=fa[x][0])
dfs2(to[i],to[i]);
}//O(n)

void build(int x,int l,int r){
int mid=(l+r)>>1,ls=x<<1,rs=ls|1;mn[x]=inf;
if(l!=r)build(ls,l,mid),build(rs,mid+1,r);
}//O(n)

void init(){
int i,u,v,dis;
read(n),read(m);
li[0]=Line(0,inf);
for(i=1;i<n;i++){
read(u),read(v),read(dis);
to[++tmp]=v;nxt[tmp]=h[u];h[u]=tmp;d[tmp]=dis;
to[++tmp]=u;nxt[tmp]=h[v];h[v]=tmp;d[tmp]=dis;
}
dfs1(1);dfs2(1,1);build(1,1,n);
}//O(n)

inline void maintain(int x,int l,int r){
if(l<r)mn[x]=min(mn[x<<1],mn[x<<1|1]);else mn[x]=inf;
mn[x]=min(mn[x],min(li[flag[x]].F(va[l]),li[flag[x]].F(va[r])));
}//O(1)

void up(int t,int y,int l,int r){
int mid=(l+r)>>1,x=flag[t];
ll lk=li[x].a,lb=li[x].b,u=li[y].a,v=li[y].b;
ll x1=va[l]*u+v,y1=va[r]*u+v,x2=va[l]*lk+lb,y2=va[r]*lk+lb;
if(x1<=x2&&y1<=y2)flag[t]=y;
else if(x1>=x2&&y1>=y2)return ;
else {
if(u<lk){
ll tmp=(v-lb)/(lk-u)+1;
if(tmp<=va[mid])swap(y,flag[t]),up(t<<1,y,l,mid);
else up(t<<1|1,y,mid+1,r);
} else{
ll tmp=(lb-v-1)/(u-lk);
if (tmp>va[mid])swap(y,flag[t]),up(t<<1|1,y,mid+1,r);
else up(t<<1,y,l,mid);
}
}
maintain(t,l,r);
}//O(logn)

void add(int x,int l,int r,int s,int t,int id){
if(l==s&&r==t){up(x,id,l,r);return;}
int mid=(l+r)>>1,ls=x<<1,rs=ls|1;
if(t<=mid)add(ls,l,mid,s,t,id);else
if(s>mid)add(rs,mid+1,r,s,t,id);else
add(ls,l,mid,s,mid,id),add(rs,mid+1,r,mid+1,t,id);
maintain(x,l,r);
}//O(log^2n)

inline void paint(int fr,int to,int a,int b){
int p=lca(fr,to),u=fr,v=to;
li[++cnt]=Line(-a,a*(ll)deep[fr]+b);
while(bel[u]!=bel[p]){
add(1,1,n,dfn[bel[u]],dfn[u],cnt);
u=fa[bel[u]][0];
}
add(1,1,n,dfn[p],dfn[u],cnt);
li[++cnt]=Line(a,(ll)a*(deep[fr]-2*deep[p])+b);
while(bel[v]!=bel[p]){
add(1,1,n,dfn[bel[v]],dfn[v],cnt);
v=fa[bel[v]][0];
}
add(1,1,n,dfn[p],dfn[v],cnt);
}//O(log^3n)

ll qrymn(int x,int l,int r,int s,int t){
if(l==s&&r==t)return mn[x];
int mid=(l+r)>>1,ls=x<<1,rs=ls|1;
ll now=min(li[flag[x]].F(va[s]),li[flag[x]].F(va[t])),last=inf;
if(t<=mid)last=qrymn(ls,l,mid,s,t);
else if(s>mid)last=qrymn(rs,mid+1,r,s,t);
else last=min(qrymn(ls,l,mid,s,mid),qrymn(rs,mid+1,r,mid+1,t));
return min(last,now);
}//O(log n)

inline ll ask(int fr,int to){
ll res=inf;int p=lca(fr,to),u=fr,v=to;
while(bel[u]!=bel[p]){
res=min(res,qrymn(1,1,n,dfn[bel[u]],dfn[u]));
u=fa[bel[u]][0];
}
res=min(res,qrymn(1,1,n,dfn[p],dfn[u]));
while(bel[v]!=bel[p]){
res=min(res,qrymn(1,1,n,dfn[bel[v]],dfn[v]));
v=fa[bel[v]][0];
}
res=min(res,qrymn(1,1,n,dfn[p],dfn[v]));
return res;
}//O(log^2n)

void work(){
int i,opt,u,v,a,b;
for(i=1;i<=m;i++){
read(opt);read(u),read(v);
if(opt==1){
read(a),read(b);
paint(u,v,a,b);
} else {
printf("%lld\n",ask(u,v));
}
}
}//O(nlog^3n)

int main(){
init();work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: