由於點能夠隨便走,因此對於每一個聯通塊,答案爲邊數/2向下取整。ios
用相似Tarjan的方式,對於每一個聯通塊創建一棵搜索樹,儘可能讓每個節點的兒子兩兩配對,若是作不到就用上頭頂的天線。c++
#include<cstdio> #include<iostream> #include<cstring> #include<vector> using namespace std; const int N=2e5+5; int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } int n,m; int to[N<<1],head[N],nxt[N<<1],tot=1,vis[N],yet[N<<1]; vector<int> ans; void add(int x,int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } void dfs(int x,int f,int e) { if(vis[x])return ; vis[x]=1; vector<int> son; for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==f)continue; dfs(y,x,i); } for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==f||yet[i])continue; son.push_back(i); yet[i^1]=1; } for(int i=0;i<son.size();i++) { if(i&1)ans.push_back(x); ans.push_back(to[son[i]]); } if(son.size()%2) { if(e) { ans.push_back(x); ans.push_back(f); yet[e]=1; } else ans.pop_back(); } } int main() { n=read();m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); add(x,y);add(y,x); } for(int i=1;i<=n;i++) if(!vis[i])dfs(i,0,0); cout<<ans.size()/3<<endl; int now=0; for(int i=1;i<=ans.size()/3;i++) printf("%d %d %d\n",ans[now++],ans[now++],ans[now++]); return 0; }
從原排列入手比較困難,咱們求出這個排列的$pos$數組($pos[a[i]]=i$),那麼問題轉化爲相鄰項且絕對值之差$\ge K$的能夠交換。最後實際上仍是讓字典序最小,由於讓前面的權值儘可能小和權值小的儘可能靠前是同樣的。git
若是在這個序列上有$|pos_i-pos_j|<K,i<j$,那麼$pos_i$和$pos_j$的相對位置就已經肯定了,至關因而一種限制。不妨把這種限制看成一條有向邊,建圖跑優先隊列拓撲獲得結果。數組
但這樣建邊時空雙炸,由於若是存在$i \rightarrow j, i \rightarrow k,j \rightarrow k$,那麼$i \rightarrow k$的邊就是無用的。真正須要建的是在兩端值域符合條件的下標最小的那兩個點。(兩段值域分別爲$[pos_i-K+1,pos_i-1]$和$[pos_i+1,pos_i+K-1]$)ui
因此維護一棵權值線段樹,每次查詢符合條件的最小下標便可。spa
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<vector> using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } const int N=5e5+5,M=2e6+2,inf=0x3f3f3f3f; int n,a[N],pos[N],K,deg[N]; int abss(int x){return x>0?x:-x;} int to[M],head[N],nxt[M],tot; priority_queue<int,vector<int>,greater<int> > q; int ans[N],cnt; void add(int x,int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; deg[y]++; } #define ls(k) (k)<<1 #define rs(k) (k)<<1|1 int minx[N<<2]; void build(int k,int l,int r) { minx[k]=inf; if(l==r)return ; int mid=l+r>>1; build(ls(k),l,mid); build(rs(k),mid+1,r); minx[k]=min(minx[ls(k)],minx[rs(k)]); } void update(int k,int l,int r,int pos,int val) { if(l==r){minx[k]=val;return ;} int mid=l+r>>1; if(pos<=mid)update(ls(k),l,mid,pos,val); else update(rs(k),mid+1,r,pos,val); minx[k]=min(minx[ls(k)],minx[rs(k)]); } int ask(int k,int l,int r,int L,int R) { if(L>R)return inf; if(L<=l&&R>=r)return minx[k]; int res=inf; int mid=l+r>>1; if(L<=mid)res=min(res,ask(ls(k),l,mid,L,R)); if(R>mid)res=min(res,ask(rs(k),mid+1,r,L,R)); return res; } int main() { n=read();K=read(); for(int i=1;i<=n;i++) a[i]=read(),pos[a[i]]=i; build(1,1,n); for(int i=n;i;i--) { int res=ask(1,1,n,pos[i]+1,min(pos[i]+K-1,n)); if(res!=inf)add(pos[i],pos[res]); res=ask(1,1,n,max(1,pos[i]-K+1),pos[i]-1); if(res!=inf)add(pos[i],pos[res]); update(1,1,n,pos[i],i); } for(int i=1;i<=n;i++) if(!deg[i])q.push(i); while(!q.empty()) { int x=q.top();q.pop(); ans[x]=++cnt; for(int i=head[x];i;i=nxt[i]) { int y=to[i]; deg[y]--; if(!deg[y])q.push(y); } } for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }
sb題。答案爲邊權和。blog
#include<bits/stdc++.h> using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } const int N=1e5+5; typedef long long ll; int n; ll ans=0; int main() { n=read(); for(int i=1;i<n;i++) { read();read();ans+=read(); } cout<<ans<<endl; return 0; }