HDU 6315 Naive Operations

http://acm.hdu.edu.cn/showproblem.php?pid=6315

题目

In a galaxy far, far away, there are two integer sequence $a$ and $b$ of length $n$.

$b$ is a static permutation of $1$ to $n$. Initially a is filled with zeroes.

There are two kind of operations:

1. add l r: add one for $a_l,a_{l+1}\dots a_r$

2. query l r: query $\sum_{i=l}^r\lfloor ai/bi \rfloor$

Input

There are multiple test cases, please read till the end of input file.

For each test case, in the first line, two integers n,q, representing the length of a,b and the number of queries.

In the second line, n integers separated by spaces, representing permutation b.

In the following q lines, each line is either in the form 'add l r' or 'query l r', representing an operation.

$1 \leqslant n,q \leqslant 100000, 1 \leqslant l \leqslant r\leqslant n$, there're no more than 5 test cases.

Output

Output the answer for each 'query', each one line.

题解

其实根本不会做……

$\lfloor a/b \rfloor = \frac{a-a\%b}{b}$,记录$a$和$a\%b$比较麻烦,因此记录$\frac{a-a\%b}{b}=\boldsymbol{v}$和$a\%b=\boldsymbol{b}$(我就喜欢乱用符号= =)

那么只需某处$\boldsymbol{b}=0$就将v单点修改+1,容易用线段树写出来……(注意可能同时有多个地方=0)

因为$n,q \leqslant 100000$,b又是一个1~n的排列,所以所有和小于$\sum_{i=1}^n\frac{n}{i}=n(\ln{n}+\gamma+\frac{1}{2n})\approx n\ln{n}<10^8$,所以可以用int存

但是为了确定某处的$\boldsymbol{b}$,直接暴力$q\times2n>10^9$肯定超时,因此需要技巧……

因为并不是所有的$\boldsymbol{b}$每时每刻都为0,所以还需要点技巧,将$\boldsymbol{b}$设为$b-a\%b$,所以只需要关心最小的那个$\boldsymbol{b}$,同样可以用线段树维护(+区间),每次维护$\log{n}$

加起来$\mathcal{O}(n\log{n})$

查询的时候并不需要向下和向上更新

还要注意更新延迟变量$\text{d}\boldsymbol{b}$时不要写成等号= =

 

AC代码

#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<set>
#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#define PERE(r,x,y) for(register int r=(x); r>=(y); r--)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__),fflush(stdout)
#else
#define DBG(...) (void)0
#endif
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

char ch; int si;
char buf[1<<21],*p1=buf,*p2=buf;
int beof = 0;
#define gc() (beof?EOF:(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(beof=EOF):*p1++))

template<class T>
inline void read(T &x) {
    x=0; si=1; for(ch=gc();!isdigit(ch) && ch!='-';ch=gc()) if(beof) return;
    if(ch=='-'){si=-1,ch=gc();} for(;isdigit(ch);ch=gc())x=x*10+ch-'0';
    x*=si;
}
//template<class T, class...A> inline void read(T &x, A&...a){read(x); read(a...);}

#define MAXN 100007
int b[MAXN];

struct node {
    int v,b,db;
    int l,r;
} st[MAXN*4];

inline void st0(int p, int l, int r) {
    st[p].l=l, st[p].r=r, st[p].v=st[p].db=0;
    if(l==r) {
        st[p].b=b[l];
        return;
    }
    int m=(l+r)>>1;
    st0(p*2,l,m);
    st0(p*2+1,m+1,r);
    st[p].b=min(st[p*2].b,st[p*2+1].b);
}

inline void spreadb(int p) {
    if(st[p].db) {
        st[p*2].db+=st[p].db; st[p*2].b-=st[p].db;
        st[p*2+1].db+=st[p].db; st[p*2+1].b-=st[p].db;
        st[p].db=0;
    }
}

inline void op_C(int p) {
    if(st[p].l==st[p].r) {
        st[p].v++; st[p].b=b[st[p].l];
        return;
    }
    spreadb(p);
    if(!st[p*2].b) op_C(p*2);
    if(!st[p*2+1].b) op_C(p*2+1);
    st[p].v=st[p*2].v+st[p*2+1].v;
    st[p].b=min(st[p*2].b, st[p*2+1].b);
}

inline void opA(int p, int l, int r) {
    if(l<=st[p].l && r>=st[p].r) {
        st[p].b--; st[p].db++;
        if(st[p].b==0) {
            op_C(p);
        }
        return;
    }
    spreadb(p);
    int m=(st[p].l+st[p].r)>>1;
    if(l<=m) opA(p*2,l,r);
    if(r>m) opA(p*2+1,l,r);
    st[p].v=st[p*2].v+st[p*2+1].v;
    st[p].b=min(st[p*2].b, st[p*2+1].b);
}

inline int opQ(int p, int l, int r) {
    if(l<=st[p].l && r>=st[p].r) {
        return st[p].v;
    }
    int m=(st[p].l+st[p].r)>>1;
    int ans=0;
    if(l<=m) ans+=opQ(p*2,l,r);
    if(r>m) ans+=opQ(p*2+1,l,r);
    return ans;
}

int main() {
#ifdef sahdsg
    freopen("in.txt","r",stdin);
#endif
    int n,q;
    read(n);read(q);
    while(!beof) {
        REPE(i,1,n) read(b[i]);
        st0(1,1,n);
        while(0<q--) {
            char k; do k=gc(); while(isspace(k));
            int l,r; read(l); read(r);
            if(k=='a') opA(1,l,r);
            else printf("%d\n", opQ(1,l,r));
        }
        read(n); read(q);

    }
    return 0;
}

 

转载于:https://www.cnblogs.com/sahdsg/p/10828831.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值