[CSP-S模擬測試62]題解

A.Graph

由於點能夠隨便走,因此對於每一個聯通塊,答案爲邊數/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;
}

 

B.Permutatin

從原排列入手比較困難,咱們求出這個排列的$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;
}

 

 

C.Tree

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;
}
相關文章
相關標籤/搜索