传送门:戳我
在cf上做的镜像赛,结果不是很妙啊。。
这题是用时最长但并没有在比赛内写出来(事实上在赛后还话了大概五小时调试才找出错误)
首先不难发现我们需要一棵线段树,(其实一开始我考虑的是主席树)。。。
然后发现很难维护区间信息。于是,考虑权值线段树(然而实际上是sugar大佬提醒我要用权值线段树)。
考虑扫描线。把每天销售方案的进出信息用一个邻接表存起来,我这里用的vector实现。然后每天该进的进,该出的出(根据差分思想,物品销售到r天,在r+1天出,我在这里卡了10分钟。。),处理完,然后在权值线段树上找到K所在的结点。
这里解释一下,就是找到当前可用的物品的第K个。以前没接触过这种类型的查询,,然后写了一个二分答案,,最后结果是NlogNlogN,没卡过1e6(哭)。比赛结束后在sugar大佬的指导下,把查找改成了logN的查找。就是找权值线段树上找第K个元素。这里对于查询一个权值线段树一个非叶子结点第a个元素,判断左子树的总数是否大于a,大于则递归到左子树,否则递归到右子树(记得a要减去左子树的元素个数,因为你递归下来查找的是右子树第b个元素,而原来的a是左子树的元素个数+b)。
然后我们还需要一棵线段树,以单价为区间,维护信息为取完这些需要多少钱。举个例子解释,比如我查询l到r,返回结果是买完大于等于l元,小于等于r元的所有物品的总价钱。然后不难发现,这棵线段树的结构和我们之前的权值线段树是一样的且更新是同步的。所以可以并到一起写。
这里搞定后然后处理细节问题。
如果一个时刻,扫描线(权值线段树)上所有元素之和小于等于K,那么我显然直接取完,进入下一天。
如果大于K,那么二分找到需要取到f元才能取到大于等于K个物品。我们会发现,取完1到f可能会取多,那么减去取多的部分产生的价钱。也就是在权值线段树上查找取到f有几个物品,然后减去K,差值乘上f就是要减去的部分的价钱。
然后把每天的值加起来,就是最后的答案了。
对本蒟蒻来说代码实现难度略高,调试略难。
以下为代码:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> #define maxn 1000005 using namespace std; vector<int>in[maxn]; vector<int>out[maxn]; namespace solution{ long long ANS=0; inline void read(int &x) { x=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x*=f; } int N,K,M,n; struct node{ long long l,r; long long sum; long long add; }tree[maxn<<2]; inline void push_up(int rt) { tree[rt].add=tree[rt<<1].add+tree[rt<<1|1].add; tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum; } void build(int rt,int l,int r) { tree[rt].l=l;tree[rt].r=r; if(l==r) return ; long long mid=l+r>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } void update(int rt,int p,long long x) { //cout<<"update note: "<<tree[rt].l<<" "<<tree[rt].r<<" "<<p<<" "<<x<<endl; if(tree[rt].l==tree[rt].r) { tree[rt].sum+=x; tree[rt].add+=x*p; return ; } int mid=tree[rt].l+tree[rt].r>>1; if(p<=mid) update(rt<<1,p,x); else update(rt<<1|1,p,x); push_up(rt); } long long query(int rt,int l,int r) { //cout<<"query note: "<<tree[rt].l<<" "<<tree[rt].r<<" "<<l<<" "<<r<<endl; if(l<=tree[rt].l&&tree[rt].r<=r) return tree[rt].sum; int mid=tree[rt].l+tree[rt].r>>1; long long ans=0; if(l<=mid) ans+=query(rt<<1,l,r); if(r>mid) ans+=query(rt<<1|1,l,r); return ans; } long long query_add(int rt,int l,int r) { // cout<<"query note: "<<tree[rt].l<<" "<<tree[rt].r<<" "<<tree[rt].add<<endl; if(l<=tree[rt].l&&tree[rt].r<=r) return tree[rt].add; int mid=tree[rt].l+tree[rt].r>>1; long long ans=0; if(l<=mid) ans+=query_add(rt<<1,l,r); if(r>mid) ans+=query_add(rt<<1|1,l,r); return ans; } struct plan{ int l,r,p,c; friend bool operator < (plan a,plan b) { return a.l<b.l; } }plan[maxn]; void getin() { read(N);read(K);read(M); for(int i=1;i<=M;i++) { read(plan[i].l);read(plan[i].r); read(plan[i].c);read(plan[i].p); n=max(n,plan[i].p); in[plan[i].l].push_back(i); out[plan[i].r+1].push_back(i); } } long long find(int rt,int k) { // cout<<"find note: "<<tree[rt].l<<" "<<tree[rt].r<<" "<<tree[rt<<1].sum<<endl; if(tree[rt].l==tree[rt].r) return tree[rt].l; int mid=tree[rt].l+tree[rt].r>>1; if(tree[rt<<1].sum>=k) return find(rt<<1,k); else return find(rt<<1|1,k-tree[rt<<1].sum); /* int l=1,r=n,mid,ans=n; while(l<=r) { mid=l+r>>1; //cout<<"find note: "<<l<<" "<<r<<" "<<mid<<" "<<query(1,1,mid)<<endl; if(query(1,1,mid)>=K) r=mid-1,ans=mid; else l=mid+1; } return ans;*/ } void work() { for(int i=1;i<=N;i++) { for(vector<int>::iterator it=in[i].begin();it!=in[i].end();it++) { int top=*it; //cout<<"in note: "<<top<<" "<<plan[top].p<<" "<<plan[top].c<<" "; update(1,plan[top].p,plan[top].c); //cout<<query(1,1,plan[top].p)<<endl; } for(vector<int>::iterator it=out[i].begin();it!=out[i].end();it++) { int top=*it; //cout<<"out note:"<<top<<endl; update(1,plan[top].p,plan[top].c*-1); } long long tot=query(1,1,n); int f=0; if(tot<=K) ANS+=query_add(1,1,n); else { f=find(1,K); long long d=query_add(1,1,f)-(query(1,1,f)-K)*f; // cout<<"NOTE: "<<query_add(1,1,f)<<" "<<query(1,1,f)<<endl; ANS+=d; } //cout<<"day:"<<i<<" "<<f<<" "<<ANS<<endl; } } void put_out() { printf("%lld",ANS); } void solve() { getin(); build(1,1,n); work(); put_out(); } } int main() { solution::solve(); }