P2345 [USACO04OPEN] MooFest G - 洛谷

P5094 [USACO04OPEN] MooFest G 加强版 - 洛谷

这题用到树状数组,首先我们肯定要以v从小到大排序,这样我们从前向后遍历时max{vi,vj}=vi,j<i。vi确定了我们就要确定\sum_{1}^{i-1}\left | xi-xj \right |。首先要将数据离散化,这里相同的数离散化为同一值和不同值都没有影响,因为相减会抵消。我们找到比他小的数的和sum,数的个数n,那么相减的绝对值之和就是n*xi-sum,同理,找到比他大的数的和sum,数的个数n,那么相减的绝对值之和就是 sum-n*xi

#include<bits/stdc++.h>
#define ll long long
#define samplepassediscorrect for(;;)
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x&(-x))
#define N 20050
using namespace std;
struct point{
	ll v,x;
}arr[N];
int n,b[N],temp[N];
bool cmp(point &s1,point &s2){return s1.v<s2.v;}
struct Fenwick_Tree{
	ll tree[N]={0};
	void update(ll x,ll d){
		while(x<=n){
			tree[x]+=d;
			x+=lowbit(x);
		}
	}
	ll sum(ll x){
		ll ans=0;
		while(x>0){
			ans+=tree[x];
			x-=lowbit(x);
		}
		return ans;
	}
}r1,r2; 
int main(){
jiasu;
cin>>n;
for(int i=1;i<=n;i++)
	cin>>arr[i].v>>arr[i].x,temp[i]=arr[i].x;
sort(temp+1,temp+1+n);
int cnt=0;
for(int i=1;i<=n;i++){
	if(b[temp[i]]==0){
		b[temp[i]]=++cnt;//离散化 
	}
}
sort(arr+1,arr+1+n,cmp);
ll ans=0;
for(int i=1;i<=n;i++){
	r1.update(b[arr[i].x],arr[i].x);
	r2.update(b[arr[i].x],1);
	ans+=arr[i].v*(arr[i].x*r2.sum(b[arr[i].x]-1)-r1.sum(b[arr[i].x]-1)+r1.sum(n)-r1.sum(b[arr[i].x])-arr[i].x*(r2.sum(n)-r2.sum(b[arr[i].x])));
}
cout<<ans;	
	return 0;
} 

P3902 递增 - 洛谷

 很明显这题是让求最长上升子序列长度的,我们需要用二分优化。具体方法自行了解。

#include<bits/stdc++.h>
#define ll long long
#define samplepassediscorrect for(;;)
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x&(-x))
#define N 50050
using namespace std;
int n,a,arr[100005],m=0;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
	cin>>a;
	if(a>arr[m]) arr[++m]=a;
	else arr[lower_bound(arr+1,arr+1+m,a)-arr]=a;
}
cout<<n-m;
	return 0;
} 

 P1774 最接近神的人 - 洛谷

其实就是逆序数

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
struct node{
	ll r,l,sum,lz;
}tree[3000005];
struct point{
	ll x,num;
}a[500005];
bool cmp(point &s1,point &s2){
	return s1.x<s2.x;
}
ll n,arr[500005];
void push_down(int i){//下传函数
	if(tree[i].lz!=0){
		tree[i*2].lz+=tree[i].lz;
		tree[i*2+1].lz+=tree[i].lz;
		tree[i*2].sum+=tree[i].lz*(tree[i*2].r-tree[i*2].l+1);
		tree[i*2+1].sum+=tree[i].lz*(tree[i*2+1].r-tree[i*2+1].l+1);
		tree[i].lz=0;
	}
	return;
}
void build(int i,int l,int r){//建树
	tree[i].l=l,tree[i].r=r;
	tree[i].lz=0;
	if(l==r) return; 
	int mid=(l+r)/2;
	build(2*i,l,mid);
	build(2*i+1,mid+1,r);
}
void add(int i,int l,int r,int k){//区间加减
	if(tree[i].l>=l&&tree[i].r<=r){	
		tree[i].sum+=k*(tree[i].r-tree[i].l+1);
		tree[i].lz+=k;
		return;
	}
	push_down(i);
	if(tree[i*2].r>=l) add(i*2,l,r,k);
	if(tree[i*2+1].l<=r) add(i*2+1,l,r,k);
	tree[i].sum=tree[2*i].sum+tree[2*i+1].sum;
	return;
}
ll search(int i,int l,int r){//查询
	if(tree[i].l>=l&&tree[i].r<=r) return tree[i].sum;
	if(tree[i].r<l||tree[i].l>r) return 0;
	push_down(i);
	ll ans=0;
	if(tree[i*2].r>=l) ans+=search(i*2,l,r);
	if(tree[i*2+1].l<=r) ans+=search(i*2+1,l,r);
	return ans;
}
int main()
{
jiasu;
cin>>n;
for(int i=1;i<=n;i++){
	cin>>a[i].x;
	a[i].num=i;
}
sort(a+1,a+1+n,cmp);
ll now=0,cnt=0;
for(int i=1;i<=n;i++){
	if(a[i].x!=now){
		now=a[i].x;
		arr[a[i].num]=++cnt;
	}
	else arr[a[i].num]=cnt;
}
build(1,1,n);
ll ans=0;
for(int i=n;i>=1;i--){
	ans+=search(1,1,arr[i]-1);
	add(1,arr[i],arr[i],1);
}
cout<<ans;
	return 0;
}

P1966 [NOIP 2013 提高组] 火柴排队 - 洛谷

严谨的证明这里不讲,凭感觉我们让\sum (a_i - b_i)^2最小,我们应该让他们从小到大排序,这样一一对应得到的应该时最小值,但是都让他们从小到大排序的移动代价太高。我们让第一个序列作为基准,将第二个序列移动为第一个序列。首先我们要将两个序列都离散化。

例如离散化后:

a:  2   6  5  1  3  4

b:  3  2  5   4  6  1

a是基准排序,我们得到inva(a的反函数)

inva[1] = 4

inva[2] = 1

inva[3] = 5

inva[4] = 6

inva[5] = 3

inva[6] = 2

再得到b相对于a的位置序列

5  1  3  6  2  4

之后我们求这个序列逆序数就好了

#include<bits/stdc++.h>
#define ll long long
#define samplepassediscorrect for(;;)
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x&(-x))
#define N 100050
using namespace std;
struct point{
	ll x,num;
}a[N],b[N];
const ll mod=1e8-3;
ll n,inva[N],invb[N],temp[N],ans=0;
bool cmp(point &s1,point &s2){return s1.x<s2.x;}
struct Fenwick_Tree{
	ll tree[N]={0};
	void update(ll x,ll d){
		while(x<=n){
			tree[x]+=d;
			x+=lowbit(x);
		}
	}
	ll sum(ll x){
		ll ans=0;
		while(x>0){
			ans+=tree[x];
			x-=lowbit(x);
		}
		return ans;
	}
}r; 
int main(){
cin>>n;
for(int i=1;i<=n;i++){
	cin>>a[i].x;
	a[i].num=i;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
	inva[i]=a[i].num;
}
for(int i=1;i<=n;i++){
	cin>>b[i].x;
	b[i].num=i;
}
sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++){
	invb[b[i].num]=inva[i];
}
for(int i=n;i>=1;i--){
	r.update(invb[i],1);
	ans=(r.sum(invb[i]-1)+ans)%mod;
}
cout<<ans%mod;
	return 0;
} 

P1996 约瑟夫问题 - 洛谷

 本人懒省事,直接用vector硬模拟了

#include<bits/stdc++.h>
#define ll long long
#define samplepassediscorrect for(;;)
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define N 200005
using namespace std;
vector<int>arr;
int n,m,now=0;
int main()
{
jiasu;
cin>>n>>m;
m--;
for(int i=1;i<=n;i++) arr.push_back(i);
while(arr.size()){
	n=arr.size();
	now=(now+m)%n;
	cout<<arr[now]<<" ";
	arr.erase(arr.begin()+now);
}
	return 0;
}

 P1972 [SDOI2009] HH的项链 - 洛谷

先将所有区间以r从小到大排序,对于一个区间,我们只关心最靠右的数,比如1,2,3,1

我们只在意第四个1,第一个1是可以忽略的,这里有点像是优先队列。所以我们从前向后遍历访问区间,不断添加新数,将老数归零。求前缀和就行。

#include<bits/stdc++.h>
#define ll long long
#define samplepassediscorrect for(;;)
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x&(-x))
#define N 1000050
using namespace std;
struct ask{
	int l,r,num;
}a[N];
ll n,arr[N],m,last[N],ans[N];
bool cmp(ask &s1,ask &s2){return s1.r<s2.r;}
struct Fenwick_Tree{
	ll tree[N]={0};
	void update(ll x,ll d){
		while(x<=n){
			tree[x]+=d;
			x+=lowbit(x);
		}
	}
	ll sum(ll x){
		ll ans=0;
		while(x>0){
			ans+=tree[x];
			x-=lowbit(x);
		}
		return ans;
	}
}r; 
int main(){
jiasu;
cin>>n;
for(int i=1;i<=n;i++)
	cin>>arr[i];
cin>>m;
for(int i=1;i<=m;i++){
	cin>>a[i].l>>a[i].r;
	a[i].num=i;
}
sort(a+1,a+1+m,cmp);
int now=1;
for(int i=1;i<=m;i++){
	while(now<=a[i].r){
		r.update(now,1);
		if(last[arr[now]]!=0){
			r.update(last[arr[now]],-1);
		}
		last[arr[now]]=now;
		now++;
	}
	ans[a[i].num]=r.sum(a[i].r)-r.sum(a[i].l-1);
}
for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
	return 0;
} 

P4939 Agent2 - 洛谷

依旧用树状数组维护差分数组,这适用于区间修改单点查询。

#include<bits/stdc++.h>
#define ll long long
#define samplepassediscorrect for(;;)
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x&(-x))
#define N 10000050
using namespace std;
ll n,m,f,a,b;
struct Fenwick_Tree{
	ll tree[N]={0};
	void update(ll x,ll d){
		while(x<=n){
			tree[x]+=d;
			x+=lowbit(x);
		}
	}
	ll sum(ll x){
		ll ans=0;
		while(x>0){
			ans+=tree[x];
			x-=lowbit(x);
		}
		return ans;
	}
}r; 
int main(){
jiasu;
cin>>n>>m;
while(m--){
	cin>>f;
	if(f){
		cin>>a;
		cout<<r.sum(a)<<endl;
	}
	else{
		cin>>a>>b;
		r.update(a,1);
		r.update(b+1,-1);
	}
}
	return 0;
} 

P1438 无聊的数列 - 洛谷

这里是区间修改区间查询,所以我用线段树,我们要维护一个差分数组,第一个修改的要+k,后面的l+1——r加上d,在r+1减去k+(r-l)*d复原,求某个值就是求前缀和。 

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define samplepassediscorrect for(;;)
#define lowbit(x) (x&(-x))
#define N 5000005
using namespace std;
ll n,a[N],m,input[N],f,l,r,k,d;
struct node{long long r,l,sum,lz;};
struct Segment_Tree{
	node tree[N];
	void push_down(int i){//下传函数	
		if(tree[i].lz!=0){		
			tree[i*2].lz+=tree[i].lz;
			tree[i*2+1].lz+=tree[i].lz;
			tree[i*2].sum+=tree[i].lz*(tree[i*2].r-tree[i*2].l+1);
			tree[i*2+1].sum+=tree[i].lz*(tree[i*2+1].r-tree[i*2+1].l+1);
			tree[i].lz=0;
		}
		return;
	}
	void build(int i,int l,int r){//建树
		tree[i].l=l,tree[i].r=r;
		tree[i].lz=0;
		if(l==r){	
			tree[i].sum=input[l];
			return;
		}
		int mid=(l+r)/2;
		build(2*i,l,mid);
		build(2*i+1,mid+1,r);
		tree[i].sum=tree[2*i].sum+tree[2*i+1].sum;
	}
	void add(int i,int l,int r,int k){//区间加减
		if(tree[i].l>=l&&tree[i].r<=r){	
			tree[i].sum+=k*(tree[i].r-tree[i].l+1);
			tree[i].lz+=k;
			return;
		}
		push_down(i);
		if(tree[i*2].r>=l) add(i*2,l,r,k);
		if(tree[i*2+1].l<=r) add(i*2+1,l,r,k);
		tree[i].sum=tree[2*i].sum+tree[2*i+1].sum;
		return;
	}
	ll search(int i,int l,int r){//查询
		if(tree[i].l>=l&&tree[i].r<=r) return tree[i].sum;
		if(tree[i].r<l||tree[i].l>r) return 0;
		push_down(i);
		long long ans=0;
		if(tree[i*2].r>=l) ans+=search(i*2,l,r);
		if(tree[i*2+1].l<=r) ans+=search(i*2+1,l,r);
		return ans;
	}
}q;
int main(){
jiasu;
cin>>n>>m;
for(int i=1;i<=n;i++){
	cin>>a[i];
	input[i]=a[i]-a[i-1];
}
q.build(1,1,n+1);
while(m--){
	cin>>f;
	if(f==1){
		cin>>l>>r>>k>>d;
		q.add(1,l,l,k);
		q.add(1,l+1,r,d);
		q.add(1,r+1,r+1,-(k+(r-l)*d));
	}
	else{
		cin>>r;
		cout<<q.search(1,1,r)<<endl;
	}
}
	return 0;
}

 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐