C2-ポケモン軍(ハードバージョン)(思考+違い/ラインセグメントツリー+ dp)詳細な説明

https://codeforces.com/contest/1420/problem/C2


この質問は非常によく考えており、それも違いであることがわかりました。前から後ろを引くことと後ろから前を引くことは意味が異なります。

c1を覚えていますか?私たちは山と谷を探しています。実際、違いのアイデアを使用して山と谷を見つけると、c2の問題を引き起こす可能性があります。どういう意味ですか?

山と谷の差は中間値の差の合計でなければならないので、山と谷は差ができるかどうかと見なすことができます。

たとえば、1 2 5 4 3 6 7のように、前後の差は-1、-3、1、2、-3 、、-1、7です。そのようなものが見つかります。正の数のすべての差を加算すると、最後に取得された山と谷の最終値になります。

たとえば、5 43は53(上記の例)を見つけますが、見つかった差は実際には(5-4)+(4-3)です。

見つかった最小値は、山と谷の単調性です.2つの値の違いが答えです。

図5-4-3でシミュレートされた線を引くと、中間点はほとんど効果がないことがわかります。実際、これらの値の差です。

そして、これを発見した後、次の操作は、配列内の2つの数値の位置を変更し、そのような同様の操作を再度実行することと同じです。

交換の前に、lの表と裏が正の数であるかどうかを検討し、正の数である場合はそれらを減算し、rの表と裏が正の数であるかどうかを検討し、正の場合は減算します。l == r-1の場合は、より多くの加算とより多くの減算を防ぐために特別に判断されることに注意してください。その中に1つの状況を含めるだけです。

交換後、隣接する差が正であるかどうかを確認し、正の差を追加します。次に出力します。スワップは問題ありません。

啓発:山と谷を見つけるために、あなたは考えるために後ろの違いに行くことができます。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=3e5+100;
typedef long long LL;
LL a[maxn];
void solve()
{
	LL n,q;cin>>n>>q;
	LL res=0;
	for(LL i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(LL i=1;i<=n;i++){
		if(a[i]-a[i+1]>0) res+=(a[i]-a[i+1]);
	}
	cout<<res<<endl;
	while(q--)
	{
		LL l,r;cin>>l>>r;
		if(a[l-1]-a[l]>0) res-=(a[l-1]-a[l]);
		if(a[r-1]-a[r]>0&&l!=r-1) res-=(a[r-1]-a[r]);
		if(a[l]-a[l+1]>0) res-=(a[l]-a[l+1]);
		if(a[r]-a[r+1]>0) res-=(a[r]-a[r+1]);
		
		swap(a[l],a[r]);
		if(a[l-1]-a[l]>0) res+=(a[l-1]-a[l]);
		if(a[r-1]-a[r]>0&&l!=r-1) res+=(a[r-1]-a[r]);
		if(a[l]-a[l+1]>0) res+=(a[l]-a[l+1]);
		if(a[r]-a[r+1]>0) res+=(a[r]-a[r+1]);
		cout<<res<<endl;
	}
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--)
  {
  	memset(a,0,sizeof(a)); 
  	solve();
  }
return 0; 
}
 

最後に、ラインセグメントツリーのdpを追加します。誰かがこれを提出するのを見ました。しかし、私はこの転送を理解することはできません。

この定数はかなり大きいです。//醜いです、それはTLEになります。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
#define INF 1e18;
using namespace std;
const int maxn=3e5+100;
typedef long long LL;
int n,q;
int a[maxn];
struct Node{
	LL v[2][2];
	Node(){
		v[0][0]=v[1][1]=v[0][1]=v[1][0]=-INF;
	}
	Node(LL x){
		v[0][0]=x;
		v[1][1]=-x;
		v[0][1]=v[1][0]=-INF;
	}
	Node operator+(Node &p){
		Node ret;
		for(int i=0;i<2;i++){
			for(int j=0;j<2;j++)
			{
				ret.v[i][j]=max({v[i][j],p.v[i][j],v[i][0]+p.v[1][j],v[i][1]+p.v[0][j]});
			}
		}
		return ret;
	}
}tree[maxn*4];
void update(int p,int l,int r,int i,int x)
{
	if(l==r){
		tree[p]=Node(x);return;
	}
	int mid=(l+r)>>1;
	if(i<=mid) update(p*2,l,mid,i,x);
	if(i>mid) update(p*2+1,mid+1,r,i,x);
	tree[p]=tree[p*2]+tree[p*2+1];
}
int main(void)
{
  //cin.tie(0);std::ios::sync_with_stdio(false);
  int t;scanf("%d",&t);
  while(t--)
  {
  	scanf("%d%d",&n,&q);
  //	for(LL i=0;i<=n+10;i++) a[i]=0,update(1,1,n,i,a[i]); 
	for(int i=1;i<=n;i++) cin>>a[i],update(1,1,n,i,a[i]);
  	printf("%lld\n",tree[1].v[0][0]);
  	while(q--)
  	{
  		int l,r;scanf("%d%d",&l,&r);
  		swap(a[l],a[r]);
  		update(1,1,n,l,a[l]);
  		update(1,1,n,r,a[r]);
  		printf("%lld\n",tree[1].v[0][0]);
  	}
  }
return 0;
}
 

 

おすすめ

転載: blog.csdn.net/zstuyyyyccccbbbb/article/details/108819446