最后一题5分很爆炸。。。慎用切分。。。
双击 2923
日常一水题,记录一下左右边界就好了
取子串 2991
DP题 取子串
Paths 2954
一道关于树的图论
先来考虑一条链的情况(考试时切分把链的分都切没了。。。)
不难发现在一条链上本题就变成一道很经典的贪心了
只要根据右端点排序就可以直接贪心
其实在树上也是差不多的思路
正解是根据添加的链的两个端点的LCA的深度从大到小来排序
貌似正确性还是挺显然的
因为当我们选取一条链的时候,这两个点的LCA的子树就没掉了
那如果这个子树中存在其他合法的链怎么办
如果存在这种链,那么它的LCA深度显然要更深,必然优先考虑
选取一条链后,要将它的子树都mark掉
接下来只要判一条链的两端是否被mark就行了
这个mark的操作显然不会超时
因为每个点最多的被mark一次
这道题还有一道升级版。。。
就不是贪心这么简单了
#include
#include
#include
#include
#include
using namespace std;
#define FOR(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;++i)
#define DOR(i,a,b) for(int i=(a),i##_end_=(b);i>=i##_end_;--i)
#define INF 0x3f3f3f3f
#define M 100005
#define N 20
void chkmx(int &a,int b) {if(avoid chkmi(int &a,int b) {if(a>b)a=b;}
int MAX(int a,int b) {return a>b?a:b;}
int MIN(int a,int b) {return astruct edge {
int fr,to,lca;
} G[M];
vector<int> es[M];
int n,m;
int dep[M],Fa[M][N];
bool cmp(edge a,edge b){
return dep[a.lca]>dep[b.lca];
}
struct _LCA_{
void dfs(int s,int fr) {
dep[s]=dep[fr]+1,Fa[s][0]=fr;
FOR(i,0,es[s].size()-1) {
int y=es[s][i];
if(y==fr) continue;
dfs(y,s);
}
}
void Init(){
dfs(1,0);
FOR(j,1,N-1)FOR(i,1,n)
Fa[i][j]=Fa[Fa[i][j-1]][j-1];
}
void up(int &s,int step){
FOR(i,0,N-1){
if((1<int LCA(int a,int b){
if(dep[a]>dep[b]) swap(a,b);
up(b,dep[b]-dep[a]);
if(a==b) return a;
DOR(i,N-1,0){
if(Fa[a][i]!=Fa[b][i])
a=Fa[a][i],b=Fa[b][i];
}
return Fa[a][0];
}
void solve(){
FOR(i,1,m) G[i].lca=LCA(G[i].fr,G[i].to);
sort(G+1,G+m+1,cmp);
}
}LCA;
struct Solve{
bool mark[M];
int a,b,ans;
void Input(){
cin>>n>>m;
FOR(i,2,n) {
scanf("%d%d",&a,&b);
es[a].push_back(b);
es[b].push_back(a);
}
FOR(i,1,m)scanf("%d%d",&G[i].fr,&G[i].to);
}
void dfs(int s,int fr){
if(mark[s]) return ;
mark[s]=1;
FOR(i,0,es[s].size()-1){
int y=es[s][i];
if(y==fr) continue;
dfs(y,s);
}
}
void work(){
ans=0;
FOR(i,1,m){
if(mark[G[i].fr]||mark[G[i].to]) continue;
dfs(G[i].lca,Fa[G[i].lca][0]);
ans++;
}
cout<int main() {
Solve.Input();
LCA.Init();
LCA.solve();
Solve.work();
return 0;
}