您的位置:首页 > 其它

CF 593D LCA,贪心

2015-11-06 15:56 302 查看
题目链接:http://codeforces.com/problemset/problem/593/D

题意:给你一个含有n个点的树(2<=n<=200000),每个边有权值xi(1<=xi<=10^18),有m个询问(1<=m<=200000),每个询问别分是:1.给你一个c,从a点走到b点,每经过一个边c = c / xi,c为整数,向下取整,输出最后c的值。2.改变某条边的值,改变的值一定要比原来小,且大于等于1。

思路:对于询问a,b,找出其公共祖先,然后从任意一点出发向祖先走,走的过程中更新c值。因为边值要等于1,要么大于1。对于所有大于1的边,显然这种边最多走64次可以结束。对于等于1的边,向上递归到边值不为1的点,并把原来点的父亲直接标记到这个点,下次往上递归时直接到这个点,那么以后的向上递归次数也不会很多。复杂度为O(nlogc)。。。。。ps:比赛时没发现自己lca的错误,一直在调。。。后来过了pretest又在找父亲这细节写错。。。真是残念啊。。。。

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn = 200005;

int n,m;
struct ppp
{
int v,nex;
ll c;
}e[maxn * 4];
ll c;
int head[maxn];
int dp[maxn * 2][19],tole;
int dep[maxn],pos[maxn],last[maxn * 2],pre[maxn];
int qian[maxn];
int cnt;
void make_edge(int u,int v,ll c)
{
e[tole].c = c;e[tole].v = v,e[tole].nex = head[u];head[u] = tole++;
}
void dfs(int u,int fa,int deep)
{
dep[u] = deep;
pos[u] = ++cnt;
last[cnt] = u;
pre[u] = fa;
int v;
for(int i = head[u];~i;i = e[i].nex)
{
v = e[i].v;
if(v == fa)continue;
qian[v] = i;
dfs(v,u,deep + 1);
pos[u] = ++cnt;
last[cnt] = u;
}
}
void ST()
{
for(int i = 1;i <= cnt;i++)
dp[i][0] = last[i];
for(int j = 1;(1 << j) <= cnt;j++)
for(int i = 1;i + (1 << j) - 1 <= cnt;i++)
{
dp[i][j] = dp[i][j - 1];
if(dep[dp[i + (1 << (j - 1))][j - 1]] < dep[dp[i][j - 1]])dp[i][j] = dp[i + (1 << (j - 1))][j - 1];
}
}
int query(int l,int r)
{
int k = 0;
while((1 << (k + 1)) <= r - l + 1)k++;
if(dep[dp[l][k]] < dep[dp[r - (1 << k) + 1][k]])
return dp[l][k];
else return dp[r - (1 << k) + 1][k];
}
void init()
{
mem(head,-1);
tole = 0;
cnt = 0;
}
int find(int x){
if(x == 1)return 1;
if(e[qian[x]].c == 1){
return pre[x] = find(pre[x]);
}
else return x;
}
int x;
void go(int u){
if(u == 1 || u == x || dep[u] <= dep[x])return;
c = c / e[qian[u]].c;
int v;
if(e[qian[u]].c == 1)
v = find(u);
else v = pre[u];
if(c == 0 || dep[v] <= dep[x] || v == x)return;
go(v);
}
int main()
{
while(cin>>n>>m)
{
init();
for(int i = 1,a,b;i <= n - 1;i++){
scanf("%d%d%I64d",&a,&b,&c);
make_edge(a,b,c);
make_edge(b,a,c);
}
dfs(1,0,0);
ST();
qian[1] = 0;
while(m--){
int op;
int a,b;
scanf("%d",&op);
if(op == 1){
scanf("%d%d",&a,&b);
cin>>c;
int aa = a,bb = b;
if(a == b){
cout<<c<<"\n";continue;
}
a = pos[a],b = pos[b];
if(a >= b)swap(a,b);
x = query(a,b);
go(aa);
go(bb);
cout<<c<<"\n";
}else{
scanf("%d%I64d",&a,&c);
e[(a - 1) * 2].c = c;
e[(a  - 1) * 2 + 1].c = c;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: