BZOJ4889: [TJOI2017]不勤劳的图书管理员
额,这个题由于被卡评测了,于是变成了权限题。。。
本蒟蒻表示没钱氪金。。。
当然,可以去洛谷/$LOJ$搞搞事。。。
这里附上洛谷的题面。
题目描述
加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员。他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度。现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置。因为小豆被要求在接下来的m天中至少要整理一次图书。小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理。
输入输出格式
输入格式:
第一行会有两个数,n,m分别表示有n本书,m天
接下来n行,每行两个数,ai和vi,分别表示第i本书本来应该放在ai的位置,这本书有vi页,保证不会有放置同一个位置的书
接下来m行,每行两个数,xj和yj,表示在第j天的第xj本书会和第yj本书会因为读者阅读交换位置
输出格式:
一共m行,每行一个数,第i行表示前i天不去整理,第i天小豆的厌烦度,因为这个数可能很大,所以将结果模10^9 +7后输出
输入输出样例
说明
对于20%的数据,1 ≤ ai; xj; yj ≤ n ≤ 5000, m ≤ 5000, vi ≤ 10^5
对于100%的数据,1 ≤ ai; xj; yj ≤ n ≤ 50000, m ≤ 50000, vi ≤ 10^5
题解Here!
首先,题目可以转化为:
- 区间询问关键字$<x$的元素个数,和这些元素的$val$之和。
- 单点修改。
对某一本书统计厌烦度时只需这么统计:$$ans+=\text{给它作出贡献的书的总页数}+\text{给它作出贡献的书的个数}\times\text{自己的页数}$$
然后这个显然树套树维护。
我用了树状数组套动态开点权值线段树。
网上还有分块套树状数组的题解,太神了。。。
本蒟蒻好菜啊。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 50010 #define MOD 1000000007LL using namespace std; int n,m; long long ans=0; int root[MAXN]; struct Book{ int x,val; }book[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline int lowbit(int x){return x&(-x);} namespace BIT{ long long s[MAXN],sum[MAXN]; inline void add(int x,long long v){for(;x<=n;x+=lowbit(x)){s[x]++;sum[x]+=v;}} inline long long get_num(int x){long long ans=0;for(;x;x-=lowbit(x))ans+=s[x];return ans;} inline long long get_sum(int x){long long ans=0;for(;x;x-=lowbit(x))ans+=sum[x];return ans;} } namespace ST{ #define LSON(rt) a[rt].lson #define RSON(rt) a[rt].rson #define SUM(rt) a[rt].sum #define DATA(rt) a[rt].data int size=0; struct Segment_Tree{ long long sum; int data,lson,rson; }a[MAXN<<8]; void update(int k,int v,int c,int lside,int rside,int &rt){ if(!rt)rt=++size; DATA(rt)+=c;SUM(rt)+=v; if(lside==rside)return; int mid=lside+rside>>1; if(k<=mid)update(k,v,c,lside,mid,LSON(rt)); else update(k,v,c,mid+1,rside,RSON(rt)); } long long query_num(int l,int r,int lside,int rside,int rt){ if(!rt)return 0; long long ans=0; if(l<=lside&&rside<=r)return DATA(rt); int mid=lside+rside>>1; if(l<=mid)ans+=query_num(l,r,lside,mid,LSON(rt)); if(mid<r)ans+=query_num(l,r,mid+1,rside,RSON(rt)); return ans; } long long query_sum(int l,int r,int lside,int rside,int rt){ if(!rt)return 0; long long ans=0; if(l<=lside&&rside<=r)return SUM(rt); int mid=lside+rside>>1; if(l<=mid)ans+=query_sum(l,r,lside,mid,LSON(rt)); if(mid<r)ans+=query_sum(l,r,mid+1,rside,RSON(rt)); return ans; } } inline void update(int x,int k,int v,int c){for(;x<=n;x+=lowbit(x))ST::update(k,v,c,1,n,root[x]);} inline long long query_num(int x,int y,int l,int r){ if(x>y||l>r)return 0; long long ans=0; for(;y;y-=lowbit(y))ans+=ST::query_num(l,r,1,n,root[y]); for(--x;x;x-=lowbit(x))ans-=ST::query_num(l,r,1,n,root[x]); return ans; } inline long long query_sum(int x,int y,int l,int r){ if(x>y||l>r)return 0; long long ans=0; for(;y;y-=lowbit(y))ans+=ST::query_sum(l,r,1,n,root[y]); for(--x;x;x-=lowbit(x))ans-=ST::query_sum(l,r,1,n,root[x]); return ans; } void work(){ int x,y; while(m--){ x=read();y=read(); if(x==y){ printf("%lld\n",ans); continue; } if(x>y)swap(x,y); //-------------------------------------------------------------------------------- ans=(ans+query_sum(x+1,y-1,1,book[y].x-1)%MOD+query_num(x+1,y-1,1,book[y].x-1)*book[y].val%MOD)%MOD; ans=((ans-query_sum(x+1,y-1,book[y].x+1,n)%MOD+MOD)%MOD-query_num(x+1,y-1,book[y].x+1,n)*book[y].val%MOD+MOD)%MOD; //-------------------------------------------------------------------------------- ans=(ans+query_sum(x+1,y-1,book[x].x+1,n)%MOD+query_num(x+1,y-1,book[x].x+1,n)*book[x].val%MOD)%MOD; ans=((ans-query_sum(x+1,y-1,1,book[x].x-1)%MOD+MOD)%MOD-query_num(x+1,y-1,1,book[x].x-1)*book[x].val%MOD+MOD)%MOD; //-------------------------------------------------------------------------------- if(book[x].x>book[y].x)ans=(ans-book[x].val-book[y].val+MOD)%MOD; else ans=(ans+book[x].val+book[y].val)%MOD; //-------------------------------------------------------------------------------- update(x,book[x].x,-book[x].val,-1);update(y,book[y].x,-book[y].val,-1); swap(book[x].x,book[y].x);swap(book[x].val,book[y].val); update(x,book[x].x,book[x].val,1);update(y,book[y].x,book[y].val,1); //-------------------------------------------------------------------------------- printf("%lld\n",ans); } } void init(){ n=read();m=read(); for(int i=1;i<=n;i++){ book[i].x=read();book[i].val=read(); update(i,book[i].x,book[i].val,1); } for(int i=n;i>=1;i--){ BIT::add(book[i].x,book[i].val); ans=(ans+BIT::get_sum(book[i].x-1)%MOD+BIT::get_num(book[i].x-1)*book[i].val%MOD)%MOD; } } int main(){ init(); work(); return 0; }