zoukankan      html  css  js  c++  java
  • 五月&六月杂题选做

    CF1468M

    Link

    非常有意思的一道题。

    将所有集合分为 (|S_i|le sqrt n)(|S_i|>sqrt n) 两类,成为「小集合」和「大集合」。那么答案 ((i,j)) 存在于这三种情况中:

    1. (i,j) 都在大集合中;
    2. (i) 在大集合中,(j) 在小集合中;
    3. (i,j) 都在小集合中。

    ( ext{Case 1 & Case 2}) 可以一起处理,枚举大集合然后对其他集合一个一个判断即可。由于大集合数量不会超过 (mathcal O(sqrt n)),时间复杂度为 (mathcal O(nsqrt n))

    ( ext{Case 3}) 需要枚举答案中的 (i),预处理哪些集合有 (i),对这些集合判断是否有除 (i) 之外的相同元素。其流程相当于遍历了所有小集合,由于小集合的大小不会超过 (mathcal O(nsqrt n)),复杂度也为 (mathcal O(nsqrt n))

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return x*f;
    }
    const int N=4e5+10;
    vector<int> v[N],pos[N];
    int k[N],t[N];
    int cnt[N];
    int sol()
    {
    	int n=read(),sz=400;
    	for(int i=1;i<=n;i++)v[i].clear(); 
    	for(int i=1;i<=n;i++)
    	{
    		k[i]=read();
    		for(int j=1;j<=k[i];j++)v[i].push_back(read());
    	}
    	int zzt=0;
    	for(int i=1;i<=n;i++)for(int j=0;j<k[i];j++)t[++zzt]=v[i][j];
    	sort(t+1,t+zzt+1);zzt=unique(t+1,t+zzt+1)-t-1;
    	for(int i=1;i<=zzt;i++)pos[i].clear();
    	for(int i=1;i<=n;i++)for(int j=0;j<k[i];j++)
    	{
    		v[i][j]=lower_bound(t+1,t+zzt+1,v[i][j])-t;
    		if(k[i]<sz)pos[v[i][j]].push_back(i);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		if(k[i]<sz)continue;
    		for(int j=1;j<=zzt;j++)cnt[j]=0;
    		for(int j=0;j<k[i];j++)cnt[v[i][j]]=1;
    		for(int j=1;j<=n;j++)
    		{
    			if(i==j)continue;
    			int c=0;
    			for(int l=0;l<k[j];l++)c+=cnt[v[j][l]];
    			if(c>=2)return printf("%d %d
    ",i,j),0;
    		}
    	}
    	for(int i=1;i<=zzt;i++)cnt[i]=0;
    	for(int i=1;i<=zzt;i++)
    	{
    		for(int j=0;j<pos[i].size();j++)
    		{
    			int s=pos[i][j];
    			for(int l=0;l<k[s];l++)
    			{
    				if(v[s][l]==i)continue;
    				if(cnt[v[s][l]])return printf("%d %d
    ",cnt[v[s][l]],s),0;
    				cnt[v[s][l]]=s;
    			}
    		}
    		for(int j=0;j<pos[i].size();j++)
    			for(int l=0;l<k[pos[i][j]];l++)
    				cnt[v[pos[i][j]][l]]=0;
    	}
    	printf("-1
    ");
    	return 0;
    }
    int main()
    {
    	int T;scanf("%d",&T);
    	while(T--)sol();
    	return 0;
    }
    

    CF1422D

    Link

    (x) 轴排序,相邻点连边,(y) 轴同理。

    自己感性证明吧。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define int long long
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    const int N=1e5+10,M=1e6+10;
    int head[N],ver[M],nxt[M],tot=0,edge[M];
    void add(int x,int y,int z)
    {
    //	printf("add(%d, %d, %d)
    ",x,y,z);
    	ver[++tot]=y;
    	edge[tot]=z;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    int dis[N];bool vis[N];
    void dij(int S)
    {
    	priority_queue<pair<int,int> > que;
    	que.push(make_pair(0,S));
    	memset(dis,0x3f,sizeof(dis));
    	dis[S]=0;
    	while(!que.empty())
    	{
    		int x=que.top().second;que.pop();
    		if(vis[x])continue;
    		vis[x]=1;
    		for(int i=head[x];i;i=nxt[i])
    		{
    			int y=ver[i],z=edge[i];
    			if(dis[x]+z<dis[y])
    			{
    				dis[y]=dis[x]+z;
    				que.push(make_pair(-dis[y],y));
    			}
    		}
    	}
    }
    struct node
    {
    	int x,y,pos;
    	node(){}
    }a[N];
    bool cmp1(node a,node b){return a.x<b.x;}
    bool cmp2(node a,node b){return a.y<b.y;}
    signed main()
    {
    	int n=read(),m=read(),sx=read(),sy=read(),tx=read(),ty=read();
    	for(int i=1;i<=m;i++)a[i].x=read(),a[i].y=read(),a[i].pos=i;
    	int S=0,T=m+1;
    	for(int i=1;i<=m;i++)add(S,i,min(abs(a[i].x-sx),abs(a[i].y-sy)));
    	for(int i=1;i<=m;i++)add(T,i,min(abs(a[i].x-tx),abs(a[i].y-ty)));
    	
    	for(int i=1;i<=m;i++)add(i,S,abs(a[i].x-sx)+abs(a[i].y-sy));
    	for(int i=1;i<=m;i++)add(i,T,abs(a[i].x-tx)+abs(a[i].y-ty));
    	
    	sort(a+1,a+m+1,cmp1);
    	for(int i=2;i<=m;i++)
    		add(a[i].pos,a[i-1].pos,min(abs(a[i].x-a[i-1].x),abs(a[i].y-a[i-1].y))),
    		add(a[i-1].pos,a[i].pos,min(abs(a[i].x-a[i-1].x),abs(a[i].y-a[i-1].y)));
    	sort(a+1,a+m+1,cmp2);
    	for(int i=2;i<=m;i++)
    		add(a[i].pos,a[i-1].pos,min(abs(a[i].x-a[i-1].x),abs(a[i].y-a[i-1].y))),
    		add(a[i-1].pos,a[i].pos,min(abs(a[i].x-a[i-1].x),abs(a[i].y-a[i-1].y)));
    	add(S,T,abs(sx-tx)+abs(sy-ty));
    	dij(S);
    	printf("%lld",dis[T]);
    	return 0;
    }
    

    1453E

    必然是走完当前一整棵子树才能走其他子树。令 (f(i)) 表示节点 (i) 距离最近的叶子节点的距离,转移即可。

    需要特判根节点,因为前驱点只需要到根节点,不需要到其他子树。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return x*f; 
    }
    const int N=2e5+10,M=4e5+10;
    int head[N],ver[M],nxt[M],tot=0;
    void add(int x,int y)
    {
    	ver[++tot]=y;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    int f[N],ans=0;
    void dfs(int x,int fa)
    {
    	int cnt=0,mx=0,mx1=0;
    	f[x]=0x7fffffff;
    	for(int i=head[x];i;i=nxt[i])
    	{
    		int y=ver[i];if(y==fa)continue;
    		cnt++;
    		dfs(y,x);
    		f[x]=min(f[x],f[y]+1);
    		if(f[y]+1>=mx)mx1=mx,mx=f[y]+1;
    		else if(f[y]+1>mx1)mx1=f[y]+1;
    	}
    	if(!cnt){f[x]=0;return;}
    	if(x==1)
    	{
    		if(cnt>1)ans=max(ans,max(mx,mx1+1)); 
    		else ans=max(ans,mx);
    	}
    	else if(cnt>1)ans=max(ans,mx+1);
    }
    void sol()
    {
    	int n=read();
    	for(int i=1;i<=n;i++)head[i]=0;
    	tot=0;
    	for(int i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		add(u,v);add(v,u);
    	}
    	ans=0;
    	dfs(1,-1);
    	printf("%d
    ",ans);
    }
    int main()
    {
    	int T=read();
    	while(T--)sol();
    	return 0;
    }
    

    CF1404C

    显然最优方案每次是最右边的能够删的数进行删除,能够使区级内能够删除的数都删掉。考虑怎么计算能否删除,定义:

    [c_i=egin{cases}i-a_i, &i-a_ige 0\+infty, &i-a_i<0end{cases} ]

    那么前 (i) 个数中能可删数的个数 (s_i) 就有转移方程 (s_i=s_{i-1}+[s_{i-1}ge c_i])

    考虑多组询问。可以将询问离线下来按照 (r) 排序,同时维护 (f_1,f_2,cdots f_n) 表示起点为 (1,2,cdots,n),终点为 (r)(s_i)。对于新来的一个 (c_r),找到一个位置 (k) 使得 (f_1ge f_2gecdots f_kge c_r>f_{k+1}gecdots f_n),那么 (c_r) 可以对 (f_1,f_2,cdots,f_k)(+1) 的贡献。线段树维护即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    const int N=3e5+10;
    struct sgt
    {
    	struct seg
    	{
    		int l,r,add,min;
    		seg(){}
    	}t[N<<2];
    	void build(int p,int l,int r)
    	{
    		t[p].add=t[p].min=0;
    		t[p].l=l;t[p].r=r;
    		if(l==r)return;
    		int mid=(l+r)/2;
    		build(p*2,l,mid);
    		build(p*2+1,mid+1,r);
    	}
    	void pd(int p)
    	{
    		if(t[p].add)
    		{
    			t[p*2].add+=t[p].add;
    			t[p*2+1].add+=t[p].add;
    			t[p*2].min+=t[p].add;
    			t[p*2+1].min+=t[p].add;
    			t[p].add=0;
    		}
    	}
    	void modify(int p,int l,int r,int d)
    	{
    		if(l<=t[p].l&&t[p].r<=r)
    		{
    			t[p].add+=d;
    			t[p].min+=d;
    			return;
    		}
    		pd(p);
    		int mid=(t[p].l+t[p].r)/2;
    		if(l<=mid)modify(p*2,l,r,d);
    		if(r>mid)modify(p*2+1,l,r,d);
    		t[p].min=min(t[p*2].min,t[p*2+1].min); 
    	}
    	//???<x?? 
    	int query(int p,int l,int r)
    	{
    		if(l<=t[p].l&&t[p].r<=r)return t[p].min;
    		int ans=0x7fffffff,mid=(t[p].l+t[p].r)/2;
    		pd(p);
    		if(l<=mid)ans=min(ans,query(p*2,l,r));
    		if(r>mid)ans=min(ans,query(p*2+1,l,r));
    		return ans;
    	}
    }T;
    int a[N];
    struct Query
    {
    	int l,r,pos;
    	bool operator<(const Query &x)const {return r<x.r;}
    }q[N];int Ans[N];
    int main()
    {
    	int n=read(),Q=read();
    	T.build(1,1,n);
    	for(int i=1;i<=n;i++)a[i]=i-read();
    //	for(int i=1;i<=n;i++)printf("%d ",a[i]);
    	for(int i=1;i<=n;i++)if(a[i]<0)a[i]=0x3f3f3f3f;
    	for(int i=1;i<=Q;i++)
    	{
    		q[i].l=read()+1,q[i].r=n-read();
    		q[i].pos=i;
    	}
    	sort(q+1,q+Q+1);
    	int last=0;
    	for(int i=1;i<=Q;i++)
    	{
    		for(int j=last+1;j<=q[i].r;j++)
    		{
    			int L=1,R=j,ans=-1;
    			while(L<=R)
    			{
    				int mid=(L+R)/2;
    				if(T.query(1,1,mid)>=a[j])ans=mid,L=mid+1;
    				else R=mid-1;
    			}
    //			printf("a[j]=%d, ans=%d
    ",a[j],ans);
    			if(~ans)T.modify(1,1,ans,1);
    		}
    //		for(int i=1;i<=n;i++)printf("%d ",T.query(1,i,i));
    //		puts("");
    		last=q[i].r;
    		Ans[q[i].pos]=T.query(1,q[i].l,q[i].l);
    	}
    	for(int i=1;i<=Q;i++)printf("%d
    ",Ans[i]);
    	return 0;
    }
    
    

    CF1399F

    Link

    分治一下,(mathrm{calc}(x)) 算在 ([l_x,r_x]) 内能有多少个区间,递归计算 (x) 覆盖的所有子区间后就变成了带权区间覆盖问题,(mathcal O(n))(mathcal O(nlog n)) dp 即可。

    然后我nt的以为上面这个 dp 只能 (mathcal O(n^2)) 做,就歇逼了。

    总的时间复杂度是 (mathcal O(n^2))(mathcal O(n^2log n)),写的后者。

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return x*f; 
    }
    const int N=6010;
    struct node
    {
    	int l,r,pos;
    	node(){}
    }a[N];
    bool cmp(node a,node b){return a.r!=b.r?a.r<b.r:a.l>b.l;}
    vector<node> v[N];
    int f[N],m;
    struct sgt
    {
    	struct seg
    	{
    		int l,r,max;
    		seg(){}
    	}t[N<<2];
    	void build(int p,int l,int r)
    	{
    		t[p].l=l;t[p].r=r;
    		t[p].max=0;
    		if(l==r)return;
    		int mid=(l+r)/2;
    		build(p*2,l,mid);
    		build(p*2+1,mid+1,r);
    	}
    	int query(int p,int l,int r)
    	{
    		if(l>r)return 0;
    		if(l<=t[p].l&&t[p].r<=r)return t[p].max;
    		int ans=0,mid=(t[p].l+t[p].r)/2;
    		if(l<=mid)ans=max(ans,query(p*2,l,r));
    		if(r>mid)ans=max(ans,query(p*2+1,l,r));
    		return ans;
    	}
    	void modify(int p,int x,int d)
    	{
    		if(t[p].l==t[p].r){t[p].max=max(t[p].max,d);return;}
    		int mid=(t[p].l+t[p].r)/2;
    		if(x<=mid)modify(p*2,x,d);
    		else modify(p*2+1,x,d);
    		t[p].max=max(t[p*2].max,t[p*2+1].max);
    	}
    };
    int w[N],n;
    void calc(int x)
    {
    	if(f[x])return;
    	if(v[x].empty()){f[x]=1;return;}
    	sgt T;T.build(1,1,m);
    	for(int i=1;i<=n;i++)w[i]=0;
    	int ans=0;
    	for(int i=0;i<v[x].size();i++)
    	{
    		node tmp=v[x][i];
    		if(!f[tmp.pos])calc(tmp.pos);
    		w[tmp.pos]=T.query(1,1,tmp.l-1)+f[tmp.pos];
    		T.modify(1,tmp.r,w[tmp.pos]);
    		ans=max(ans,w[tmp.pos]);
    	}
    	f[x]=ans+(x!=0);
    }
    int t[N];
    void sol()
    {
    //	puts("haha");
    	n=read(),m=0;
    	for(int i=0;i<=n;i++)f[i]=0;
    	for(int i=0;i<=n;i++)v[i].clear();
    	for(int i=1;i<=n;i++)t[++m]=a[i].l=read(),t[++m]=a[i].r=read(),a[i].pos=i;
    //	puts("haha");
    	sort(t+1,t+m+1);m=unique(t+1,t+m+1)-t-1;
    	for(int i=1;i<=n;i++)a[i].l=lower_bound(t+1,t+m+1,a[i].l)-t,a[i].r=lower_bound(t+1,t+m+1,a[i].r)-t;
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i!=j&&a[i].l<=a[j].l&&a[j].r<=a[i].r)v[i].push_back(a[j]);
    	for(int i=1;i<=n;i++)v[0].push_back(a[i]);
    	for(int i=0;i<=n;i++)sort(v[i].begin(),v[i].end(),cmp);
    	calc(0);
    	printf("%d
    ",f[0]);
    }
    int main()
    {
    // 	freopen("1399F.in","r",stdin);
    	int T=read();
    	while(T--)sol();
    	return 0;
    }
    

    1268C

    Link

    贪心地想,对于一个 (k),一定是把 (1sim k) 凑到一起之后再将它们用类似冒泡排序的方式排序。排序的代价很好求,是逆序对数量,问题在于凑在一起的代价。

    假设 (1,2,cdots,k) 的位置分别是 (p_1,p_2,cdots,p_k),那么我们就是要找到一个 (p') 使得 (sum_{i=1}^k |p'-p_i|) 最小。根据初一数学,必然是取中间能得到最小,可以二分这个中间值 (p') 即可。(mathcal O(nlog^2 n))

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return x*f;
    }
    const int N=2e5+10;
    int n,p[N],id[N];
    struct bit
    {
    	int c[N];
    	bit(){memset(c,0,sizeof(c));}
    	void modify(int x,int d){for(;x<=n;x+=x&-x)c[x]+=d;}
    	int query(int x,int ans=0){for(;x;x-=x&-x)ans+=c[x];return ans;}
    }t1,t2,t3;
    int Ans[N];
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)id[p[i]=read()]=i;
    	for(int i=1;i<=n;i++)
    	{
    		Ans[i]+=t3.query(n)-t3.query(id[i]);
    		t3.modify(id[i],1);
    	}
    	for(int i=1;i<=n;i++)Ans[i]+=Ans[i-1];
    	for(int k=1;k<=n;k++)
    	{
    		t1.modify(id[k],1),t2.modify(id[k],id[k]);
    		if(k==1){printf("0 ");continue;}
    		int pos=0,l=1,r=n,ans=Ans[k];
    		while(l<=r)
    		{
    			int mid=(l+r)/2;
    			if(t1.query(mid)>=t1.query(n)-t1.query(mid))r=mid-1,pos=mid;
    			else l=mid+1;
    		}
    		int cnt1=(k+1)/2,cnt2=k/2;
    		int sum1=(pos-cnt1+1+pos)*cnt1/2,sum2=(pos+1+pos+cnt2)*cnt2/2;
    		ans+=sum1-t2.query(pos)+(t2.query(n)-t2.query(pos))-sum2;
    		printf("%lld ",ans);
    	}
    	return 0;
    }
    

    888G

    Link

    自己做出来的第一道 2300

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return x*f;
    }
    const int N=3e5+10;
    typedef long long ll;
    int f[N],a[N];
    void init(int n){for(int i=1;i<=n;i++)f[i]=i;}
    int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}
    int trie[N*30][2],sz[N*30],ed[N*30],tot=0;
    void ins(int x,int pos)
    {
    	int p=0;
    	for(int i=29;i>=0;i--)
    	{
    		int op=(x&(1<<i))!=0;
    		if(!trie[p][op])trie[p][op]=++tot;
    		p=trie[p][op];
    		sz[p]++;
    	}
    	ed[p]=pos;
    }
    void del(int x)
    {
    	int p=0;
    	for(int i=29;i>=0;i--)
    	{
    		int op=(x&(1<<i))!=0;
    		p=trie[p][op];
    		sz[p]--;
    	}
    }
    int query(int x)
    {
    	int p=0;
    	for(int i=29;i>=0;i--)
    	{
    		int op=(x&(1<<i))!=0;
    		if(trie[p][op]&&sz[trie[p][op]])p=trie[p][op];
    		else p=trie[p][op^1];
    	}
    	return ed[p];
    }
    int n;ll ans=0; 
    vector<int> v[N];
    struct node
    {
    	int u,v,w;
    	bool operator <(const node &x)const {return w<x.w;}
    };
    void sol()
    {
    	int cnt=0;
    	for(int i=1;i<=n;i++)cnt+=getf(i)==i;
    	if(cnt==1)return;
    	for(int i=1;i<=n;i++)v[i].clear();
    	for(int i=1;i<=n;i++)v[getf(i)].push_back(i);
    	vector<node> s;
    	for(int i=1;i<=n;i++)
    	{
    		if(v[i].empty())continue;
    		int Min=0x7fffffff,pos=0,pos1=0;
    		for(int j=0;j<v[i].size();j++)
    		{
    			int x=v[i][j];
    			del(a[x]);
    		}
    		for(int j=0;j<v[i].size();j++)
    		{
    			int x=v[i][j],tmp=query(a[x]);
    			if((a[x]^a[tmp])<Min)Min=(a[x]^a[tmp]),pos=x,pos1=tmp;
    		}
    		s.push_back((node){pos,pos1,Min});
    		for(int j=0;j<v[i].size();j++)
    		{
    			int x=v[i][j];
    			ins(a[x],x);
    		}
    	}
    	sort(s.begin(),s.end());
    	for(int i=0;i<s.size();i++)
    	{
    		int u=s[i].u,v=s[i].v,w=s[i].w;
    		if(getf(u)!=getf(v))ans+=w,f[getf(v)]=getf(u);
    	}
    	sol();
    }
    signed main()
    {
    	n=read();init(n);
    	for(int i=1;i<=n;i++)a[i]=read();
    	sort(a+1,a+n+1);
    	n=unique(a+1,a+n+1)-a-1;
    	for(int i=1;i<=n;i++)ins(a[i],i);
    	sol();
    	printf("%lld",ans);
    	return 0;
    }
    

    Codeforces 1251E1&E2

    非常nb的一道题。

    有一个巧妙的转化:将投票转化成给这 (n) 个人排一个顺序,若排在第 (i) 个位置的人的 (m) 满足 (m<i),那么这个人没有代价,反之需要花费 (p_i) 的代价,求最小代价。反过来想,就是让满足 (m<i) 的所有人排得尽量前,那么用一个 priority_queue 维护即可。

    #include<iostream>
    #include<queue>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return x*f;
    }
    typedef long long ll;
    const int N=2e5+10;
    struct node{int m,c;}a[N];
    bool cmp(node a,node b){return a.m<b.m;}
    void sol()
    {
    	int n=read();
    	ll ans=0;
    	for(int i=1;i<=n;i++)a[i].m=read(),ans+=(a[i].c=read());
    	sort(a+1,a+n+1,cmp);
    	priority_queue<int> que;
    	for(int i=1,j=1;i<=n;i++)
    	{
    		while(j<=n&&a[j].m<i)que.push(a[j++].c);
    		if(!que.empty())ans-=que.top(),que.pop();
    	}
    	printf("%lld
    ",ans);
    }
    int main()
    {
    	int T=read();
    	while(T--)sol();
    	return 0;
    }
    
  • 相关阅读:
    nginx实战
    apache定制错误页面
    openstack虚拟机获取不到ip
    ansible-galera集群部署(13)
    kubernetes监控(12)
    kubernets部署sock-shop微服务电商平台(11)
    用ConfigMap管理配置(10)
    k8s管理机密信息(9)
    shell编程(2)
    shell练习题集合
  • 原文地址:https://www.cnblogs.com/juruo-zzt/p/14794107.html
Copyright © 2011-2022 走看看