HDU6203 补题LCA复习+dfs序
这个题目其实算是贪心吧,感觉自己贪心有点菜,这几天要把贪心练一下了
建树,dfs什么的就不说了,这里主要讲下思路
就是建完树后,给你两个点
然后求出他们的lca,将这两个点u,v和lca,dlca(lca点的深度)存在一个结构体数组中
然后将这个数组按深度从大到小排序
接着遍历这个数组
每次看u,v有没有访问过,如果有就不管,如果没有,就将他们的lca点拿掉并将lca点的所有子节点记为访问过并且ans++
最后输出ans就好了
其实,为什么这样做可以呢
对于一个u,v,我们要做的就是把他们分开,我们就可以拿掉链接u,v上的点的任意一个就好,那么就会出现一个问题
如果有另外两个点的lca正好经过这一条链,那么如果我只拿掉那个点的lca就好了
如果我们这样排序的话,其实就保证了这种情况,也就是保证了最优
还有一点,我们标记已访问过的点时,不需要用到树链剖分,因为是对子树的操作,dfs序就可以了
这个题目有点手残,用的线段树求的lca,代码量直接爆炸了
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 60010using namespace std;struct Edge
{int next,en;
};struct Save
{int node,dep;Save(int n,int d){node=n;dep=d;}Save(){}
};bool operator < (Save a,Save b)
{return a.dep<b.dep;}struct Node
{int u,v;Save lca;
};
bool operator < (Node a,Node b)
{return a.lca.dep<b.lca.dep;}bool cmp(Node a,Node b)
{return a.lca.dep>b.lca.dep;}Edge edge[maxn];
Node node[maxn];
Save save[maxn*2];
Save segt[maxn<<2];//线段树的大小为节点大小的4倍int head[maxn],cnte;
int dfsx,in[maxn],out[maxn],vis[maxn],cntn;
int LCAArray[maxn*2];void init()
{memset(head,-1,sizeof(head));memset(vis,0,sizeof(vis));cnte=0;cntn=0;dfsx=0;
}void addedge(int st,int en)
{cnte++;edge[cnte].en=en;edge[cnte].next=head[st];head[st]=cnte;return;
}void addnode(int u,int v,Save lca)
{cntn++;node[cntn].u=u;node[cntn].v=v;node[cntn].lca=lca;return;
}void dfs(int root,int depth)//dfs没问题
{dfsx++;in[root]=dfsx;vis[root]=1;save[dfsx].dep=depth;save[dfsx].node=root;for (int k=head[root];k!=-1;k=edge[k].next)if (!vis[edge[k].en]){dfs(edge[k].en,depth+1);dfsx++;save[dfsx].dep=depth;save[dfsx].node=root;}out[root]=dfsx;return;
}void build(int root,int beg,int en)//线段树建树函数
{if (beg==en)segt[root]=save[beg];else{build(root*2,beg,(beg+en)/2);build(root*2+1,(beg+en)/2+1,en);if (segt[root*2]<segt[root*2+1])segt[root]=segt[root*2];else segt[root]=segt[root*2+1];}return;
}Save query(int root,int l,int r,int ql,int qr)
{if(l == ql && r == qr) return segt[root];int mid=(l+r)/2;if(qr <= mid) return query(root*2,l,mid,ql,qr);else if(ql >= mid + 1) return query(root*2+1,mid+1,r,ql,qr);return min(query(root*2,l,mid,ql,mid), query(root*2+1,mid + 1,r,mid + 1,qr));
}void initLCA(int n)
{dfs(0,1);build(1,1,dfsx);
}Save LCA(int u,int v)
{int qbeg,qend;if (in[u]<in[v]){qbeg=in[u];qend=in[v];}else{qbeg=in[v];qend=in[u];}return query(1,1,dfsx,qbeg,qend);
}struct Segt
{int val,addmark;
};Segt segtf[maxn<<2];void pushdown(int root)
{if (segtf[root].addmark!=0){segtf[root*2].val+=segtf[root].addmark;segtf[root*2].addmark+=segtf[root].addmark;segtf[root*2+1].val+=segtf[root].addmark;segtf[root*2+1].addmark+=segtf[root].addmark;segtf[root].addmark=0;}return;
}int queryf(int root,int l,int r,int poi)
{if(l==r) return segtf[root].val;pushdown(root);int mid=(l+r)/2;if(poi <= mid) return queryf(root*2,l,mid,poi);else if(poi >= mid + 1) return queryf(root*2+1,mid+1,r,poi);
}void updatef(int root,int rst,int ren,int beg,int en,int val)
{if (rst>=beg&&ren<=en){segtf[root].val+=val;segtf[root].addmark+=val;}else if (rst>en||ren<beg) {return;}else{pushdown(root);int mid=(rst+ren)/2;updatef(root*2,rst,mid,beg,en,val);updatef(root*2+1,mid+1,ren,beg,en,val);segtf[root].val=segtf[root*2].val&&segtf[root*2+1].val;}
}int main()
{int n,m;while(~scanf("%d",&n)){init();for (int k=1;k<=n;k++){int st,en;scanf("%d %d",&st,&en);addedge(st,en);addedge(en,st);}n++;initLCA(n);scanf("%d",&m);for (int k=1;k<=m;k++){int u,v;Save lca;scanf("%d %d",&u,&v);lca=LCA(u,v);addnode(u,v,lca);}sort(node+1,node+1+cntn,cmp);memset(segtf,0,sizeof(segtf));int ans(0);for (int k=1;k<=cntn;k++){int u,v,l;u=node[k].u;v=node[k].v;l=node[k].lca.node;if ((queryf(1,1,dfsx,in[u])==0)&&(queryf(1,1,dfsx,in[v])==0)){ans++;updatef(1,1,dfsx,in[l],out[l],1);}}printf("%d\n",ans);}return 0;
}
HDU6203 补题LCA复习+dfs序相关推荐
- LCA ---- E. Tree Queries[LCA或者dfs序的解法]
题目链接 题目大意:就是给你一颗树,然后qqq次询问每次询问会给出kkk个点,要求你判断一下这些点是否在存在一条从1到某个点u的链使得这k个点都在这条链上或者距离这条链距离为1的位置上 解法1:dfs ...
- BC div2补题以及 复习模除 逆元__BestCoder Round #78 (div.2)
第一题没话说 智商欠费 加老柴辅导终于过了 需要在意的是数据范围为2的63次方-1 三个数相加肯定爆了 四边形的定义 任意边小于其余三边之和 换句话说就是 最长边小于其余三边之和 这样的话问题转化为 ...
- BZOJ2588 Count on a tree DFS序+LCA+值域主席树
Count on a tree 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答 ...
- CodeForces - 1328E Tree Queries(dfs序/LCA)
题目链接:点击查看 题目大意:给出一棵以点 1 为根节点的树,接下来有 m 次询问,每次询问给出 k 个点,题目问我们能否找到一个点 u ,使得从根节点到点 u 的简单路径,到 k 个点的每个点的距离 ...
- A and B and Lecture Rooms CodeForces - 519E LCA+dfs序
看到这个题的第一个思路就是就是统计以每一个点为根的所有节点个数,然后具体就分情况讨论一下即可. 因为刚刚学习了dfs序,这个题就用了dfs序来通过进出时间戳来相减表示其为根的子节点个数. 分情况 我们 ...
- 牛客 - Colorful Tree(dfs序+LCA)
题目链接:点击查看 题目大意:给出一棵 n 个节点构成的数,每个节点都有一个颜色,现在需要执行 m 次操作,每次操作分为如下两种类型: Q x:回答所有颜色为 x 的节点构成的连通子图含有的最少边数 ...
- HDU - 6203 ping ping ping(LCA+dfs序+线段树)
题目链接:点击查看 题目大意:给出一棵由n+1个节点组成的数,节点编号为0~n(这个无关紧要,预处理时所有节点以及n都自增1即可转换为正常的模型了),现在给出m组节点u和v,问若想让m组u和v都断开连 ...
- HDU 6203 ping ping ping (LCA+DFS序)
思路参考:http://blog.csdn.net/DorMOUSENone/article/details/77929604 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法 ...
- POJ - 2763 Housewife Wind LCA+dfs序+线段树
q次询问求两个点之间的距离,并且可以随时修改某条边的长度,最短距离可以用lca来求,但是树上维护每一个点到root的距离必须要用dfs序来记录时间戳,在dfs的时候顺便记录每一条边(u,v)对应的v节 ...
最新文章
- 手把手教你用Python实现自动特征工程
- html语言的空格键,如何在如何在HTML中插入空格中插入空格
- ASP.NET 2.0中轻松实现网站换肤
- 历史命令与实时记录(redhat6.8)
- 使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题
- Android4.4 Sensor APP--HAL代码流程
- Java语言基础--集合
- python游戏设计的课题背景_游戏设计论文开题报告
- WiFi之协议栈要点
- Unity3D 使用UGUI实现公告牌
- [uwsgi-body-read] Error reading 65536 bytes. Content-Length: 560903 consumed: 0 left: 560903 message
- openstack常用命令
- 绕过阿里云盾进行XSS
- 肌酐研究之Biovision肌酐合成试剂盒
- iOS企业证书的申请与制作
- VUE饿了么学习笔记(6)goods界面滚动和点击联动的实现
- 《Python程序设计与算法基础教程(第二版)》江红 余青松 全部章节的课后习题,上机实践,课后答案,案例研究
- 新手领导需要避开的5个职场暗礁,个个都深藏杀机
- js实现匹配到文字设置为红色
- 当mybatisPlus与tk.mybatis遇到更新