数据结构day2 lca
2018-02-06 21:57
204 查看
丁叔叔的恐怖红包
小庆住在一个很特别的国度里,它有N 个城市,并且只建了N ?1 条双向路,但神奇的是任意两个城市
都可以通过这些路连接起来。小庆最近在研究寒假的旅游计划,有时她想快速地知道两个城市之间的距
离,于是找你来帮帮解决。
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v;w,表示城市u 和城市v 之间有一条长为w 的路。
接下来1 行,包含一个整数Q,表示小庆有Q 个询问。
接下来Q 行,每行两个整数u; v,表示小庆想知道u 和v 这两个城市之间的距离。
Output
对于小庆的每个询问,输出两个城市之间的距离。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
const int p=20;
int wi[maxn],dep[maxn],dis[maxn],pos[maxn],nxt[maxn],tov[maxn],head[maxn],anc[maxn][p+1];
int q,n,tot=0,root;
void add(int i,int j,int w)
{
tot++;
tov[tot]=j;
nxt[tot]=head[i];
wi[tot]=w;
head[i]=tot;
}
void dfs(int u,int f)
{
anc[u][0]=f;
for (int i=1;i<=p;i++)
anc[u][i]=anc[anc[u][i-1]][i-1];
for (int i=head[u];i;i=nxt[i])
{
int v=tov[i];
if (v==f)
continue;
dep[v]=dep[u]+1;
dis[v]=dis[u]+wi[i];
dfs(v,u);
}
}
int lca(int u,int v)
{
if (dep[u]<dep[v])
swap(u,v);
int t=dep[u]-dep[v];
for (int i=0;t;t>>=1,i++){
if (t&1)
u=anc[u][i];
}if (u==v)
return u;//惨痛教训
for (int i=p;anc[u][0]!=anc[v][0];i--)
if (anc[u][i]!=anc[v][i])
{
u=anc[u][i];
v=anc[v][i];
}
return anc[u][0];
}
int main()
{
freopen("distance.in","r",stdin);
freopen("distance.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n-1;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dep[1]=1;
dis[1]=0;
dfs(1,1);
scanf("%d",&q);
for (int i=1;i<=q;i++)
{
int x,y,ans=0;
scanf("%d%d",&x,&y);
int lca1=lca(x,y);
printf("%d\n",dis[x]+dis[y]-2*dis[lca1]);
}
return 0;
}
/*
4
1 2 3
1 3 4
2 4 2
3
1 1
1 4
2 3
*/(承上题)小漫是小庆那个国家的国王,她住在1 号城市,u 号城市如果到1 必定经过v 号城市,我们则
称v 号城市管辖u 号城市(v 号城市也管辖自己)。过年了,小漫想给国家的一些城市发红包,每次她会
给u 号城市管辖的每个城市发放w 的红包,有时,她也想知道某个城市或被某个城市管辖的城市一共得
了多少红包。如下:
• give u w :表示将u 号城市管辖的每个城市发w 的红包。
• single u :表示询问u 号城市得了多少红包。
• all u :表示询问u 号城市管辖的城市一共得了多少红包。
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v,表示城市u 和城市v 之间有一条路。
接下来1 行,包含一个整数Q,表示小漫有Q 个操作。
接下来Q 行,每行是上面三种操作的一种。
Output
对每个询问,输出其答案。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=200005;
int flag[N*2],out
,in
,tot,dd,tov
,head
,nex
;
long long f[N*2],tag[N*2];
char s1[15];
void add(int x,int y)
{
tot++;
tov[tot]=y;
nex[tot]=head[x];
head[x]=tot;
}
void dfs(int u,int f)
{
dd++;
in[u]=dd;
for(int i=head[u];i;i=nex[i])
{
int v=tov[i];
if(v==f) continue;
dfs(v,u);
}
out[u]=dd;
}
void update(int o)
{
f[o]=f[o*2]+f[o*2+1];
}
void push_down(int o,int l,int r)
{
int mid=(l+r)/2;
if(flag[o]==1)
{
f[o*2]+=(mid-l+1)*tag[o];
f[o*2+1]+=(r-mid)*tag[o];
tag[o*2]+=tag[o];
tag[o*2+1]+=tag[o];
flag[o*2]=1;
flag[o*2+1]=1;
tag[o]=flag[o]=0;
}
}
long long query(int o,int l,int r,const int L,const int R)
{
if(L<=l&&R>=r)
return f[o];
push_down(o,l,r);
int mid=(r+l)/2;
long long ans=0;
if(L<=mid) ans+=query(o*2,l,mid,L,R);
if(R>mid) ans+=query(o*2+1,mid+1,r,L,R);
return ans;
}
void change(int o,int l,int r,const int L,const int R,long long data)
{
if(L<=l&&R>=r)
{
f[o]+=data*(r-l+1);
tag[o]+=data;
flag[o]=1;
return;
}
push_down(o,l,r);
int mid=(l+r)/2;
if(L<=mid) change(o*2,l,mid,L,R,data);
if(R>mid) change(o*2+1,mid+1,r,L,R,data);
update(o);
}
int main()
{
freopen("redpacket.in","r",stdin);
freopen("redpacket.out","w",stdout);
int m,n,y,x;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
scanf("%d",&m);
dfs(1,1);
for(int i=1;i<=m;i++)
{
scanf("%s",s1);
if(s1[0]=='g')
{
scanf("%d%d",&x,&y);
change(1,1,n,in[x],out[x],y);
}
if(s1[0]=='s')
{
scanf("%d",&x);
long long la=query(1,1,n,in[x],out[x]);
if(in[x]==out[x])
{
printf("%I64d\n",la);
}
else
{
long long ans;
long long la2=query(1,1,n,in[x]+1,out[x]);
ans=la-la2;
printf("%I64d\n",ans);
}
}
if(s1[0]=='a')
{
scanf("%d",&x);
long long la=query(1,1,n,in[x],out[x]);
printf("%I64d\n",la);
}
}
return 0;
}
/*
5
1 2
1 3
2 4
2 5
3
give 1 5
single 2
all 2
*/(承上题)小漫觉得那样发红包有些无聊,于是决定每次给u 号城市到v 号城市简单路径经过的城市发
红包(当然包括u 和v 本身),考虑到你们还太年轻,就只问你们单个城市的红包了:
• give u v w :给u 到v 的简单路径上的城市w 的红包
• single u :询问到目前为止u 号城市得到的红包
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v,表示城市u 和城市v 之间有一条路。
接下来1 行,包含一个整数Q,表示小漫有Q 个操作。
接下来Q 行,每行是上面两个操作中的一个。
Output
对于每个询问,输出其答案。
跑一波std指针
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010;
const int M = N + N;
const int P = 16;
struct Node {
long long sum;
Node *ls, *rs;
void update() {
sum = ls->sum + rs->sum;
}
}pool[N*3], *tail=pool, *root;
int n, q;
int head
, dest[M], last[M], etot;
int in
, out
, seq
, dep
, anc
[P+1], idc;
void adde( int u, int v ) {
etot++;
dest[etot] = v;
last[etot] = head[u];
head[u] = etot;
}
void dfs( int u, int f ) {
seq[++idc] = u;
in[u] = idc;
anc[u][0] = f;
for( int p = 1; p <= P; p++ )
anc[u][p] = anc[anc[u][p-1]][p-1];
for( int t = head[u]; t; t = last[t] ) {
int v = dest[t];
if( v == f ) continue;
dep[v] = dep[u] + 1; // idy!!!!!!!!! I'm angry!!!
dfs( v, u );
}
out[u] = idc;
}
int lca( int u, int v ) {
if( dep[u] < dep[v] ) swap(u,v);
int t = dep[u] - dep[v];
for( int p = 0; t; t>>=1, p++ )
if( t & 1 ) u = anc[u][p];
if( u == v ) return u;
for( int p = P; anc[u][0] != anc[v][0]; p-- )
if( anc[u][p] != anc[v][p] )
u = anc[u][p], v = anc[v][p];
return anc[u][0];
}
Node *build( int lf, int rg ) {
Node *nd = ++tail;
if( lf == rg ) {
nd->sum = 0;
} else {
int mid = (lf + rg) >> 1;
nd->ls = build( lf, mid );
nd->rs = build( mid+1, rg );
nd->sum = 0;
}
return nd;
}
long long query( Node *nd, int lf, int rg, int L, int R ) {
if( L <= lf && rg <= R )
return nd->sum;
int mid = (lf + rg) >> 1;
long long rt = 0;
if( L <= mid )
rt += query( nd->ls, lf, mid, L, R );
if( R > mid )
rt += query( nd->rs, mid + 1, rg, L, R );
return rt;
}
void modify( Node *nd, int lf, int rg, int pos, int delta ) {
if( lf == rg ) {
nd->sum += delta;
return;
}
int mid = (lf + rg)>>1;
if( pos <= mid )
modify( nd->ls, lf, mid, pos, delta );
else
modify( nd->rs, mid+1, rg, pos, delta );
nd->update();
}
int main() {
freopen ( "redpacket2.in", "r", stdin ) ;
freopen ( "redpacket2.out", "w", stdout ) ;
scanf( "%d", &n );
for( int i = 1; i < n; i++ ) {
int u, v;
scanf( "%d%d", &u, &v );
adde( u, v );
adde( v, u );
}
idc = 0;
dep[1] = 1;
dfs( 1, 1 );
root = build( 1, idc );
scanf( "%d", &q );
while( q-- ) {
char ss[100];
int u, v, w;
scanf( "%s", ss );
if( ss[0] == 'g' ) {
scanf( "%d%d%d", &u, &v, &w );
int ca = lca(u,v);
modify( root, 1, idc, in[u], w );
modify( root, 1, idc, in[v], w );
modify( root, 1, idc, in[ca], -w );
if( ca != 1 )
modify( root, 1, idc, in[anc[ca][0]], -w );
} else {
scanf( "%d", &u );
printf( "%lld\n", query(root,1,idc,in[u],out[u]) );
}
}
}
lca版子记错爆0异常难受
小庆住在一个很特别的国度里,它有N 个城市,并且只建了N ?1 条双向路,但神奇的是任意两个城市
都可以通过这些路连接起来。小庆最近在研究寒假的旅游计划,有时她想快速地知道两个城市之间的距
离,于是找你来帮帮解决。
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v;w,表示城市u 和城市v 之间有一条长为w 的路。
接下来1 行,包含一个整数Q,表示小庆有Q 个询问。
接下来Q 行,每行两个整数u; v,表示小庆想知道u 和v 这两个城市之间的距离。
Output
对于小庆的每个询问,输出两个城市之间的距离。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
const int p=20;
int wi[maxn],dep[maxn],dis[maxn],pos[maxn],nxt[maxn],tov[maxn],head[maxn],anc[maxn][p+1];
int q,n,tot=0,root;
void add(int i,int j,int w)
{
tot++;
tov[tot]=j;
nxt[tot]=head[i];
wi[tot]=w;
head[i]=tot;
}
void dfs(int u,int f)
{
anc[u][0]=f;
for (int i=1;i<=p;i++)
anc[u][i]=anc[anc[u][i-1]][i-1];
for (int i=head[u];i;i=nxt[i])
{
int v=tov[i];
if (v==f)
continue;
dep[v]=dep[u]+1;
dis[v]=dis[u]+wi[i];
dfs(v,u);
}
}
int lca(int u,int v)
{
if (dep[u]<dep[v])
swap(u,v);
int t=dep[u]-dep[v];
for (int i=0;t;t>>=1,i++){
if (t&1)
u=anc[u][i];
}if (u==v)
return u;//惨痛教训
for (int i=p;anc[u][0]!=anc[v][0];i--)
if (anc[u][i]!=anc[v][i])
{
u=anc[u][i];
v=anc[v][i];
}
return anc[u][0];
}
int main()
{
freopen("distance.in","r",stdin);
freopen("distance.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n-1;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dep[1]=1;
dis[1]=0;
dfs(1,1);
scanf("%d",&q);
for (int i=1;i<=q;i++)
{
int x,y,ans=0;
scanf("%d%d",&x,&y);
int lca1=lca(x,y);
printf("%d\n",dis[x]+dis[y]-2*dis[lca1]);
}
return 0;
}
/*
4
1 2 3
1 3 4
2 4 2
3
1 1
1 4
2 3
*/(承上题)小漫是小庆那个国家的国王,她住在1 号城市,u 号城市如果到1 必定经过v 号城市,我们则
称v 号城市管辖u 号城市(v 号城市也管辖自己)。过年了,小漫想给国家的一些城市发红包,每次她会
给u 号城市管辖的每个城市发放w 的红包,有时,她也想知道某个城市或被某个城市管辖的城市一共得
了多少红包。如下:
• give u w :表示将u 号城市管辖的每个城市发w 的红包。
• single u :表示询问u 号城市得了多少红包。
• all u :表示询问u 号城市管辖的城市一共得了多少红包。
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v,表示城市u 和城市v 之间有一条路。
接下来1 行,包含一个整数Q,表示小漫有Q 个操作。
接下来Q 行,每行是上面三种操作的一种。
Output
对每个询问,输出其答案。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=200005;
int flag[N*2],out
,in
,tot,dd,tov
,head
,nex
;
long long f[N*2],tag[N*2];
char s1[15];
void add(int x,int y)
{
tot++;
tov[tot]=y;
nex[tot]=head[x];
head[x]=tot;
}
void dfs(int u,int f)
{
dd++;
in[u]=dd;
for(int i=head[u];i;i=nex[i])
{
int v=tov[i];
if(v==f) continue;
dfs(v,u);
}
out[u]=dd;
}
void update(int o)
{
f[o]=f[o*2]+f[o*2+1];
}
void push_down(int o,int l,int r)
{
int mid=(l+r)/2;
if(flag[o]==1)
{
f[o*2]+=(mid-l+1)*tag[o];
f[o*2+1]+=(r-mid)*tag[o];
tag[o*2]+=tag[o];
tag[o*2+1]+=tag[o];
flag[o*2]=1;
flag[o*2+1]=1;
tag[o]=flag[o]=0;
}
}
long long query(int o,int l,int r,const int L,const int R)
{
if(L<=l&&R>=r)
return f[o];
push_down(o,l,r);
int mid=(r+l)/2;
long long ans=0;
if(L<=mid) ans+=query(o*2,l,mid,L,R);
if(R>mid) ans+=query(o*2+1,mid+1,r,L,R);
return ans;
}
void change(int o,int l,int r,const int L,const int R,long long data)
{
if(L<=l&&R>=r)
{
f[o]+=data*(r-l+1);
tag[o]+=data;
flag[o]=1;
return;
}
push_down(o,l,r);
int mid=(l+r)/2;
if(L<=mid) change(o*2,l,mid,L,R,data);
if(R>mid) change(o*2+1,mid+1,r,L,R,data);
update(o);
}
int main()
{
freopen("redpacket.in","r",stdin);
freopen("redpacket.out","w",stdout);
int m,n,y,x;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
scanf("%d",&m);
dfs(1,1);
for(int i=1;i<=m;i++)
{
scanf("%s",s1);
if(s1[0]=='g')
{
scanf("%d%d",&x,&y);
change(1,1,n,in[x],out[x],y);
}
if(s1[0]=='s')
{
scanf("%d",&x);
long long la=query(1,1,n,in[x],out[x]);
if(in[x]==out[x])
{
printf("%I64d\n",la);
}
else
{
long long ans;
long long la2=query(1,1,n,in[x]+1,out[x]);
ans=la-la2;
printf("%I64d\n",ans);
}
}
if(s1[0]=='a')
{
scanf("%d",&x);
long long la=query(1,1,n,in[x],out[x]);
printf("%I64d\n",la);
}
}
return 0;
}
/*
5
1 2
1 3
2 4
2 5
3
give 1 5
single 2
all 2
*/(承上题)小漫觉得那样发红包有些无聊,于是决定每次给u 号城市到v 号城市简单路径经过的城市发
红包(当然包括u 和v 本身),考虑到你们还太年轻,就只问你们单个城市的红包了:
• give u v w :给u 到v 的简单路径上的城市w 的红包
• single u :询问到目前为止u 号城市得到的红包
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v,表示城市u 和城市v 之间有一条路。
接下来1 行,包含一个整数Q,表示小漫有Q 个操作。
接下来Q 行,每行是上面两个操作中的一个。
Output
对于每个询问,输出其答案。
跑一波std指针
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010;
const int M = N + N;
const int P = 16;
struct Node {
long long sum;
Node *ls, *rs;
void update() {
sum = ls->sum + rs->sum;
}
}pool[N*3], *tail=pool, *root;
int n, q;
int head
, dest[M], last[M], etot;
int in
, out
, seq
, dep
, anc
[P+1], idc;
void adde( int u, int v ) {
etot++;
dest[etot] = v;
last[etot] = head[u];
head[u] = etot;
}
void dfs( int u, int f ) {
seq[++idc] = u;
in[u] = idc;
anc[u][0] = f;
for( int p = 1; p <= P; p++ )
anc[u][p] = anc[anc[u][p-1]][p-1];
for( int t = head[u]; t; t = last[t] ) {
int v = dest[t];
if( v == f ) continue;
dep[v] = dep[u] + 1; // idy!!!!!!!!! I'm angry!!!
dfs( v, u );
}
out[u] = idc;
}
int lca( int u, int v ) {
if( dep[u] < dep[v] ) swap(u,v);
int t = dep[u] - dep[v];
for( int p = 0; t; t>>=1, p++ )
if( t & 1 ) u = anc[u][p];
if( u == v ) return u;
for( int p = P; anc[u][0] != anc[v][0]; p-- )
if( anc[u][p] != anc[v][p] )
u = anc[u][p], v = anc[v][p];
return anc[u][0];
}
Node *build( int lf, int rg ) {
Node *nd = ++tail;
if( lf == rg ) {
nd->sum = 0;
} else {
int mid = (lf + rg) >> 1;
nd->ls = build( lf, mid );
nd->rs = build( mid+1, rg );
nd->sum = 0;
}
return nd;
}
long long query( Node *nd, int lf, int rg, int L, int R ) {
if( L <= lf && rg <= R )
return nd->sum;
int mid = (lf + rg) >> 1;
long long rt = 0;
if( L <= mid )
rt += query( nd->ls, lf, mid, L, R );
if( R > mid )
rt += query( nd->rs, mid + 1, rg, L, R );
return rt;
}
void modify( Node *nd, int lf, int rg, int pos, int delta ) {
if( lf == rg ) {
nd->sum += delta;
return;
}
int mid = (lf + rg)>>1;
if( pos <= mid )
modify( nd->ls, lf, mid, pos, delta );
else
modify( nd->rs, mid+1, rg, pos, delta );
nd->update();
}
int main() {
freopen ( "redpacket2.in", "r", stdin ) ;
freopen ( "redpacket2.out", "w", stdout ) ;
scanf( "%d", &n );
for( int i = 1; i < n; i++ ) {
int u, v;
scanf( "%d%d", &u, &v );
adde( u, v );
adde( v, u );
}
idc = 0;
dep[1] = 1;
dfs( 1, 1 );
root = build( 1, idc );
scanf( "%d", &q );
while( q-- ) {
char ss[100];
int u, v, w;
scanf( "%s", ss );
if( ss[0] == 'g' ) {
scanf( "%d%d%d", &u, &v, &w );
int ca = lca(u,v);
modify( root, 1, idc, in[u], w );
modify( root, 1, idc, in[v], w );
modify( root, 1, idc, in[ca], -w );
if( ca != 1 )
modify( root, 1, idc, in[anc[ca][0]], -w );
} else {
scanf( "%d", &u );
printf( "%lld\n", query(root,1,idc,in[u],out[u]) );
}
}
}
lca版子记错爆0异常难受
相关文章推荐
- spoj COT 可持久化数据结构 (LCA模版)
- 数据结构 day2
- 数据结构:线段树(树状数组、BST、LCA、
- HDU2874——Connections between cities 详解 (LCA,RMQ,数据结构,dfs序,并查集)
- SPOJ - COT Count on a tree [LCA+主席树]【数据结构】
- day2 数据结构和一些基础知识
- 2017年第0届浙江工业大学之江学院程序设计竞赛决赛 H: qwb与学姐 [MST+LCA]【数据结构】
- NOIP 2015 Day2 T3 运输计划(二分+dfs序+树上差分+倍增LCA)
- 数据结构 《18》----RMQ 与 LCA 的等价性 (一)
- 数据结构 《18》----RMQ 与 LCA 的等价性 (一)
- 【NOIP 2015 DAY2 T3】 运输计划 (树链剖分-LCA)
- HDU4912 Paths on the tree(数据结构,lca,贪心)
- Educational Codeforces Round 3 E. Minimum spanning tree for each edge LCA/(树链剖分+数据结构) + MST
- 数据结构----栈的操作
- 黑马程序员——高新技术---Java基础-集合特点和数据结构总结
- OpenCV里IplImage数据结构中的width和widthStep
- 深入浅出Redis-redis底层数据结构(上)
- [总结]数据结构真是博大精深(一)
- 常见的数据结构面试题
- 程序员面试题精选100题(02)-设计包含min函数的栈[数据结构]