[Ynoi2013]大学/我永远喜欢珂朵莉~

5 篇文章 0 订阅
4 篇文章 0 订阅

在太阳西斜的这个世界里,置身天上之森。
等这场战争结束后,不归之人和望眼欲穿的人们,人人本着正义之名。
长存不灭的过去,逐渐消逝的未来。
我回来了,纵使日薄西山,即便看不到未来,
此时此刻的光辉,盼君勿忘。
——世上最幸福的女孩

我永远喜欢珂朵莉~

5.20来切信仰题!


考虑操作 1 1 1,每次把一个区间内 x x x的倍数除以 x x x

  • x = 1 x=1 x=1的时候,显然什么都不用做
  • x ≥ 2 x\geq 2 x2的时候,一个数最坏情况下只会被除 log ⁡ \log log次(每次都除 2 2 2)就会变成 1 1 1,然后就不能再除了

所以一共操作次数最多只有 n log ⁡ r n\log r nlogr 次,其中 r = max ⁡ { a i } r=\max\{a_i\} r=max{ai},即值域

那么接下来我们就需要考虑如何快速的找出区间内是 x x x的倍数的数

我们发现,对于任意 a i ≤ 5 × 1 0 5 a_i\leq 5\times 10^5 ai5×105,他最多最多只能有 a i \sqrt{a_i} ai 个因数,所以我们考虑给每一个因数建立一棵平衡树储存所有的满足 a i a_i ai是这个因数的倍数的 i i i,那么查询的时候直接 FHQ Treap \text{FHQ Treap} FHQ Treap按照区间 s p l i t split split就可以

这些平衡树的建立我们可以提前利用 O ( n r ) O(n\sqrt{r}) O(nr )的时间进行预处理

那么接下来我们需要一种数据结构能够支持 单点修改、区间查询 那么这个时候我们就可以想到建立树状数组来维护这个东西

最多删除 n log ⁡ r n\log r nlogr次,每次需要花费 log ⁡ n \log n logn的时间

那么均摊下来的复杂度就是 O ( n r + n log ⁡ n log ⁡ r ) O(n\sqrt r+n\log n\log r) O(nr +nlognlogr),空间复杂度是 O ( n r ) O(n\sqrt r) O(nr )

n = 1 0 5 , r = 5 × 1 0 5 n=10^5,r=5\times 10^5 n=105,r=5×105,时限 4 s 4s 4s,空间限制 1.22 G B 1.22GB 1.22GB(这是个什么数???)的情况下看上去可以通过(Ynoi,你懂的

同时为了追求效率,我们应该每次建树的时候建出一棵笛卡尔树,否则会有几个点T掉,每次就把需要新建的部分存到数组里面然后暴力建树就可以(下面的 b u i l d build build部分),这样就保证了建树是严格的 O ( n ) O(n) O(n)而不会有多出来的 log ⁡ \log log


做法很简单,但是坑还是不少,这里简单列几个我掉进去的坑吧

  • 我们在预处理的时候为了方便可以拿一个 v e c t o r vector vector存相应的下标然后再扔到平衡树里,但是这个时候我们必须保证 v e c t o r vector vector单调递增
  • 在遍历区间的时候,我们即使是除也需要先判断能不能除尽( 12 12 12分很可能就是挂在这里了),因为比如说有个 4 4 4,他先除了个 2 2 2,接下来又要除 4 4 4,那么这个时候他不是 4 4 4的倍数了,但是他还在 4 4 4那棵平衡树里面

卡常的话,其实这题也不怎么卡啦…

如果最后两个点T了可以看看是不是写了# define int long long,就把树状数组开longlong就够了,能快三分之一

写完这题顺便还可以把大学给A了

代码:

#include <bits/stdc++.h>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=5e5+5;
const int M=34e6+5;

template<typename T> void read(T &x){
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m,top;
int a[N];
int root[N],tot;
int q[N],len;
int son[M][2],siz[M],val[M];
ll bit[N];
int bin[M],binsiz;
vector<int> fac[N];

void add(int o,int x){
    for(;o<=n;o+=o&-o)bit[o]+=x;
}  

ll ask(int o){
    ll res=0;
    for(;o;o-=o&-o)res+=bit[o];
    return res;
}

int newnode(int x){
    int u=(!binsiz)?++tot:bin[binsiz--];
    siz[u]=1;
    val[u]=x;
    return u;
}

void update(int x){
    siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
}

int build(int l,int r){
    if(l>r)return 0;
    int mid=l+r>>1;
    int u=newnode(q[mid]);
    son[u][0]=build(l,mid-1);
    son[u][1]=build(mid+1,r);
    return update(u),u;
}

int merge(int u,int v){
    if(!u||!v)return u|v;
    int rt;
    if(rand()<rand())son[rt=u][1]=merge(son[u][1],v);
    else son[rt=v][0]=merge(u,son[v][0]);
    return update(rt),rt;
}

void split(int o,int &u,int &v,int k){
    if(!o){u=v=0;return;}
    if(val[o]<=k)split(son[u=o][1],son[o][1],v,k);
    else split(son[v=o][0],u,son[o][0],k);
    update(o);
}

void del(int &rt,int x){
    int lft,mid,rht;
    split(rt,lft,rht,x);
    split(lft,lft,mid,x-1);
    rt=merge(lft,rht);
}

void dfs(int u,int k){
    if(!u)return;
    if(son[u][0])dfs(son[u][0],k);
    if(a[val[u]]%k==0)add(val[u],-a[val[u]]+a[val[u]]/k),a[val[u]]/=k;
    if(a[val[u]]%k==0)q[++len]=val[u];
    if(son[u][1])dfs(son[u][1],k);
    bin[++binsiz]=u;
    son[u][0]=son[u][1]=siz[u]=val[u]=0;
}

int main()
{
    srand(time(0));
    read(n),read(m);
    Rep(i,1,n)read(a[i]),top=max(top,a[i]),add(i,a[i]);
    Rep(i,1,n)
        for(int j=1;j*j<=a[i];j++)
            if(a[i]%j==0){
                fac[j].push_back(i);
                if(a[i]/j!=j)fac[a[i]/j].push_back(i);
            }
    Rep(i,2,top){
        len=0;
        for(vector<int>::iterator it=fac[i].begin();it!=fac[i].end();it++)
            q[++len]=*it;
        root[i]=build(1,len);
    }
    Rep(i,1,m){
        int opt,l,r,k;
        read(opt),read(l),read(r);
        if(opt==1){
            read(k);
            if(k==1)continue;
            int lft,mid,rht;
            split(root[k],lft,rht,r);
            split(lft,lft,mid,l-1);
            len=0;
            dfs(mid,k);
            mid=build(1,len);
            root[k]=merge(merge(lft,mid),rht);
        }
        else printf("%lld\n",ask(r)-ask(l-1));
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
TokenType.SYMBOL_LEFT_PAREN) { match(TokenType.SYMBOL_LEFT_PAREN); expression(); match(TokenType.SYMBOL_RIGHT_PAREN); } else { throw new Exception("Syntax error"); } } private void match(TokenType type) throws Exception { if (tokenList.get(index).getType() == type) { index++; } else { throw new Exception("Syntax error"); } } private int getVariableAddress(String identifier) throws Exception { if (!symbolTable.containsKey(identifier)) { 这是一道程序设计竞赛题目,需要设计算法来解决。题目描述为: 有一个大小为 $ throw new Exception("Undefined variable"); } return symbolTable.get(identifier); } } ``` 在语义分析程序n\times m$ 的网格图,每个格子中有一个整数。定义一个点 $(i,j)$ 的权中,我们首先定义了四个成员变量:词法单元列表、当前处理的词法单元下标、符号表和四元式列表。其中符号表用于存储变量名和对应的内存地址,值为 $a_{i,j}$ 与其上下左右四个点权值的和的乘积,即 $a四元式列表用于存储生成的四元式。 然后,我们定义了一系列方法来进行语义分_{i,j}\times (a_{i-1,j}+a_{i+1,j}+a_{i,j-1}析和生成四元式。这些方法分别对应PL/0语言的不同语法结构,例如程序+a_{i,j+1})$。现在你需要找到一个点 $(i,j)$,使得其权值最、块、语句、表达式、项和因子。在处理每个语法结构时,我们先判断当前大,输出这个最大权值。 需要用到搜索算法或动态规划算法来解决这个问题,具体实现可以参考题目解析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值