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;
    }
    
  • 相关阅读:
    修复 Visual Studio Error “No exports were found that match the constraint”
    RabbitMQ Config
    Entity Framework Extended Library
    Navisworks API 简单二次开发 (自定义工具条)
    NavisWorks Api 简单使用与Gantt
    SQL SERVER 竖表变成横表
    SQL SERVER 多数据导入
    Devexpress GridControl.Export
    mongo DB for C#
    Devexress XPO xpPageSelector 使用
  • 原文地址:https://www.cnblogs.com/juruo-zzt/p/14794107.html
Copyright © 2011-2022 走看看