問題描述
所連接的網絡共有個站點,由於經費問題,每兩個站點之間有且僅有一條線路,這些站點中有一些損壞了,進行了次測試,每次測試兩個站點之間是否連通,由於手氣太好,他每次測試的兩個站點之間都不連通。現在想知道最少有多少個站點損壞了,並想知道一種可能的損壞數最小的損壞情況。
考慮一條路徑目前沒有選擇任何點,我們選擇哪一個點是最優的。
求出這棵樹的序。
對於每個詢問,即路徑,我們可以看做是在序上的區間。
區間記錄個量,,容易理解變量名。
我們發現,選擇是最優秀的策略。易於理解,對於每個區間,所在的位置更容易影響到其他區間。
現在的問題在於如何進行操作。
既然已經求出了序,所以我們就在這上面進行修改。
由於我們是記錄了某個的使用情況,而直接影響到的就是當前區間,所以我們就考慮用樹上點差分進行操作。
關於普通點差分的執行:。
由於是區間上進行修改與查詢,所以我們再添加一個樹狀數組。
另外貪心一下,查詢前將按照序先排個序。
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N=3e5+5;
int dep[N],fa[N][21];
int inc,to[N],nxt[N],head[N];
int n,m,k,ans,tim,l[N],r[N],vis[N],dfn[N],bit[N];
struct node {
int x,y,lca;
}ask[N];
#define lowbit(x) (x&(-x))
void swap(int &x,int &y) {
int ret=y;y=x;x=ret;
}
void ins(int x,int y) {
to[++inc]=y;nxt[inc]=head[x];head[x]=inc;
}
void add(int x,int y) {
while(x<=n) bit[x]+=y,x+=lowbit(x);
}
int getsum(int x) {
int ret=0;while(x) ret+=bit[x],x-=lowbit(x);return ret;
}
void dfs(int x) {
dfn[x]=++tim;l[x]=tim;dep[x]=dep[fa[x][0]]+1;
for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa[x][0]) fa[to[i]][0]=x,dfs(to[i]);r[x]=tim;
}
int lca(int x,int y) {
if(dep[x]<dep[y]) swap(x,y);int dlt=dep[x]-dep[y];
for(int i=20;i>=0;i--) if(dlt&(1<<i)) x=fa[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
bool cmp(node x,node y) {
return dfn[x.lca]>dfn[y.lca];
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);ins(x,y);ins(y,x);
}
dfs(1);
scanf("%d",&k);
for(int i=1;i<=k;i++) scanf("%d%d",&ask[i].x,&ask[i].y),ask[i].lca=lca(ask[i].x,ask[i].y);
std::sort(ask+1,ask+1+k,cmp);
for(int i=1;i<=k;i++) {
int x=ask[i].x,y=ask[i].y,lc=ask[i].lca;
int ret1=getsum(dfn[x]),ret2=getsum(dfn[y]);
int ret3=getsum(dfn[lc]),ret4=getsum(dfn[fa[lc][0]]);
if(ret1+ret2-ret3-ret4<=0) {
ans++;vis[lc]=1;add(dfn[lc],1);add(r[lc]+1,-1);
}
}
printf("%d\n",ans);
for(int i=1;i<=n;i++) if(vis[i]) printf("%d ",i);
return 0;
}