• SDOI2015


    SDOI一轮过去,觉得自己爆搜都会写残。。。好无奈。。。

    先修课过去,觉得自己手速慢加各种爆搜残。。。好无奈。。。

    day1T1

    题目大意:第i(1<=i<=n)种操作为将序列从左到右划分为2^{n-i+1}段,每段恰好包括2^{i-1}个数,然后整体交换其中两段。每种操作只能用一次,问有多少种不同的交换方式。

    思路:每次出现一种操作个数为x的操作序列,那么都有x!种相应的变换,因为交换这个序列中任意两个,都一定有对应的操作方法。因此我们枚举出本质不同的操作序列就可以了。从小的操作开始做,每次都分成2^i个数的2^(n-i)个块。找到不匹配的块(不是连续递增的),保存一下。如果没有,就不用进行这种操作;如果有一个,就看这个块先半部分和后半部分交换后能否满足条件;如果有两个,就有四种交换方法,分情况判断一下。根据相应的变换交换这半个块的开头和结尾的元素就可以了(之后每次的块都扩大两倍,所以不会用到中间的元素,而从小到大操作有保证了块内有序)。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int a[5000]={0},n;
    long long ans,jie[13]={0};
    void swa(int i,int j,int len)
    {
        int k;
        for (k=0;k<len;++k) swap(a[i+k],a[j+k]);
    }
    void dfs(int i,int sum)
    {
        int zhan[3]={0},totz=0,j,k,len;
        if (i==n+1)
        {
            ans+=jie[sum];return;
        }
        len=1<<i;
        for (j=1;j<=1<<n;j+=len)
        {
            if (a[j+len/2-1]+1!=a[j+len/2])
            {
                if (totz==2) return;
                else zhan[++totz]=j;
            }
        }
        if (totz==0)
            dfs(i+1,sum);
        if (totz==1)
        {
            j=zhan[totz];
            if (a[j]==a[j+len-1]+1)
            {
                swap(a[j],a[j+len/2]);
                if (len>2) swap(a[j+len/2-1],a[j+len-1]);
                dfs(i+1,sum+1);
                swap(a[j],a[j+len/2]);
                if (len>2) swap(a[j+len/2-1],a[j+len-1]);
            }
        }
        if (totz==2)
        {
            j=zhan[1];k=zhan[2];
            if (a[j+len/2-1]+1==a[k+len/2]&&a[k+len/2-1]+1==a[j+len/2])
            {
                swap(a[j],a[k]);
                if (len>2) swap(a[j+len/2-1],a[k+len/2-1]);
                dfs(i+1,sum+1);
                swap(a[j],a[k]);
                if (len>2) swap(a[j+len/2-1],a[k+len/2-1]);
                swap(a[j+len/2],a[k+len/2]);
                if (len>2) swap(a[j+len-1],a[k+len-1]);
                dfs(i+1,sum+1);
                swap(a[j+len/2],a[k+len/2]);
                if (len>2) swap(a[j+len-1],a[k+len-1]);
            }
            if (a[j+len-1]+1==a[k+len/2]&&a[j+len/2-1]+1==a[k])
            {
                swap(a[j+len/2],a[k]);
                if (len>2) swap(a[j+len-1],a[k+len/2-1]);
                dfs(i+1,sum+1);
                swap(a[j+len/2],a[k]);
                if (len>2) swap(a[j+len-1],a[k+len/2-1]);
            }
            if (a[k+len-1]+1==a[j+len/2]&&a[k+len/2-1]+1==a[j])
            {
                swap(a[j],a[k+len/2]);
                if (len>2) swap(a[j+len/2-1],a[k+len-1]);
                dfs(i+1,sum+1);
                swap(a[j],a[k+len/2]);
                if (len>2) swap(a[j+len/2-1],a[k+len-1]);
            }
        }
    }
    int main()
    {
        int i,j;
        scanf("%d",&n);
        for (i=1;i<= 1<<n;++i) scanf("%d",&a[i]);
        jie[0]=(long long)1;
        for (i=1;i<=n;++i) jie[i]=jie[i-1]*(long long)i;
        dfs(1,0);
        printf("%I64d
    ",ans);
    }
    View Code

    day1T2

    题目大意:一棵树,给出边的长度,每次操作改变一个点的信息(标记或取消标记),之后输出从一个点出发、走过所有标记点之后回到起始点的最小距离。

    思路:一轮的时候只能弱弱的写暴力,下来听TA的题解,看TA各种ac。。。其实我们每次加入一个点,都要使他尽快并到已有的路线上去,这时候我们要找两个lca:所有原来点的lca1(也就是dfs序里最两边的标记点的lca),与这个点两边两个点(也就是dfs序中离这个点最近的两个标记点)的两个lca中离这个点较近的lca2(一开始理解错了这个lca,这里距离最近才能保证答案最小)。这两个lca一定是祖孙关系(可能是一个点)。然后就分类讨论一下:如果lca1是lca2的祖先,答案就是新加入点道lca2的距离;如果反过来,答案还要加上lca1到lca2的距离。这里的距离以及求lca所要用的信息都可以在建树的时候求出(第一次写了非递归的建树)。用一个线段树来维护一下dfs序中点被标记的情况。在插入和删除的时候,要注意修改和查询线段树的顺序。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define inf 2100000000LL
    #define proof 17
    using namespace std;
    struct use{
        int st,en,va;
    }edge[200001]={0};
    struct used{
        int hi;
        long long dis;
    }dian[100001]={0};
    struct uss{
        int maxp,minp,num;
    }tree[400000];
    int tot=0,next[200001]={0},point[100001]={0},bi[100001]={0},zhan[100001]={0},kk[100001]={0},cur[100001]={0},ff[100001][18]={0};
    bool visit[100001]={false};
    void add(int st,int en,int va)
    {
        ++tot;next[tot]=point[st];point[st]=tot;
        edge[tot].st=st;edge[tot].en=en;edge[tot].va=va;
        ++tot;next[tot]=point[en];point[en]=tot;
        edge[tot].st=en;edge[tot].en=st;edge[tot].va=va;
    }
    void updata(int i)
    {
        tree[i].maxp=max(tree[i*2].maxp,tree[i*2+1].maxp);
        tree[i].minp=min(tree[i*2].minp,tree[i*2+1].minp);
        tree[i].num=tree[i*2].num+tree[i*2+1].num;
    }
    void build(int i,int l,int r)
    {
        int mid;
        if (l==r)
        {
            tree[i].maxp=-inf;tree[i].minp=inf;
            tree[i].num=0;return;
        }
        mid=(l+r)/2;
        build(i*2,l,mid);build(i*2+1,mid+1,r);
        updata(i);
    }
    void ins(int i,int l,int r,int x,int y)
    {
        int mid;
        if (l==r)
        {
            tree[i].num+=y;
            if (tree[i].num) tree[i].maxp=tree[i].minp=l;
            else
            {
                tree[i].maxp=-inf;tree[i].minp=inf;
            }
            return;
        }
        mid=(l+r)/2;
        if (x<=mid) ins(i*2,l,mid,x,y);
        else ins(i*2+1,mid+1,r,x,y);
        updata(i);
    }
    int ask(int i,int l,int r,int ll,int rr,int kk)
    {
        int mid,aaa;
        if (ll<=l&&r<=rr)
        {
            if (kk) return tree[i].maxp;
            else return tree[i].minp;
        }
        mid=(l+r)/2;
        if (kk) aaa=-inf;
        else aaa=inf;
        if (ll<=mid)
        {
            if (kk) aaa=max(aaa,ask(i*2,l,mid,ll,rr,kk));
            else aaa=min(aaa,ask(i*2,l,mid,ll,rr,kk));
        }
        if (rr>mid)
        {
            if (kk) aaa=max(aaa,ask(i*2+1,mid+1,r,ll,rr,kk));
            else aaa=min(aaa,ask(i*2+1,mid+1,r,ll,rr,kk));
        }
        return aaa;
    }
    int lca(int x,int y)
    {
        int i,j;
        if (x==y) return x;
        if (dian[x].hi>dian[y].hi) swap(x,y);
        for (i=proof;i>=0;--i)
          if (dian[x].hi<=dian[ff[y][i]].hi)
              y=ff[y][i];
        if (x==y) return x;
        for (i=proof;i>=0;--i)
        {
            if (ff[x][i]!=ff[y][i])
            {
                x=ff[x][i];y=ff[y][i];
            }
        }
        return ff[x][0];
    }
    int main()
    {
        int n,m,i,j,u,v,w,x,p1,p2,lca1,lca2,lca3;
        long long ans=0;
        scanf("%d%d",&n,&m);
        for (i=1;i<n;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        for (i=1;i<=n;++i) cur[i]=point[i];
        i=1;zhan[i]=1;u=1;bi[1]=1;visit[1]=true;
        while(i)
        {
            x=zhan[i];
            for (j=1;j<=proof;++j)
                ff[bi[x]][j]=ff[ff[bi[x]][j-1]][j-1];
            while (cur[x])
            {
                j=cur[x];cur[x]=next[cur[x]];
                if (!visit[edge[j].en])
                {
                   ++i;++u;zhan[i]=edge[j].en;
                   bi[edge[j].en]=u;dian[u].dis=dian[bi[x]].dis+(long long)edge[j].va;
                   dian[u].hi=i-1;ff[u][0]=bi[x];
                   visit[edge[j].en]=true;break;
                }
            }
            if (!cur[zhan[i]]) --i;
        }
        build(1,1,n);
        for (i=1;i<=m;++i)
        {
            scanf("%d",&j);
            j=bi[j];kk[j]=1-kk[j];u=j;
            if (tree[1].num==0)
            {
                printf("0
    ");ins(1,1,n,j,1);continue;
            }
            if (tree[1].num<=2&&kk[j]==0)
            {
                printf("0
    ");ins(1,1,n,j,-1);continue;
            }
            if (j>1) p1=ask(1,1,n,1,j-1,1);
            else p1=-inf;
            if (j<n) p2=ask(1,1,n,j+1,n,0);
            else p2=inf;
            if (kk[j])
            {
                lca1=lca(tree[1].minp,tree[1].maxp);
                ins(1,1,n,j,1);
                lca2=lca3=0;
                if (p1>-inf) lca2=lca(p1,j);
                if (p2<inf) lca3=lca(p2,j);
                if ((lca2==0)||(lca2!=0&&dian[lca2].dis<dian[lca3].dis)) lca2=lca3;
                if (dian[lca2].dis>=dian[lca1].dis)
                    ans+=dian[j].dis-dian[lca2].dis;
                if (dian[lca2].dis<dian[lca1].dis)
                    ans+=dian[j].dis-dian[lca2].dis+dian[lca1].dis-dian[lca2].dis;
            }
            else
            {
                ins(1,1,n,j,-1);
                lca1=lca(tree[1].minp,tree[1].maxp);
                lca2=lca3=0;
                if (p1>-inf) lca2=lca(p1,j);
                if (p2<inf) lca3=lca(p2,j);
                if ((lca2==0)||(lca2!=0&&dian[lca2].dis<dian[lca3].dis)) lca2=lca3;
                if (dian[lca2].dis>=dian[lca1].dis)
                  ans-=(dian[j].dis-dian[lca2].dis);
                if (dian[lca2].dis<dian[lca1].dis)
                  ans-=(dian[j].dis-dian[lca2].dis+dian[lca1].dis-dian[lca2].dis);
            }
            printf("%lld
    ",ans*2);
        }
    }
    View Code

    day1T3

    题目大意:给定一个大小为|S|的集合S,求长度为n的乘积%m为x的排列个数(modP)。

    思路:ntt+原根。O(nm^2)的暴力dp,可以用倍增的思想优化到O(m^2logn),但这样不能优化掉m^2。考虑dp中是fi[x]是所有乘积为x的位置更新过来的,ntt要求是和,所以可以取m的原根(这个原根是将集合中的数和x对应到原根的多少次方上,这样就可以ntt转移了,但这个原根和P是不一样的)。

    ntt和fft类似,因为mod,所以可以直接用整数类型存储,但wn的求法略有不同。

    判断m原根的方法直接枚举原根x,如果x的m-1所有因子次方!=1就是原根了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 40005
    #define P 1004535809LL
    #define G 3LL
    #define LL long long
    using namespace std;
    LL aa[N]={0LL},ai[N],nup,c[N]={0LL},bi[N],ci[N];
    int s[N],up,l,m,po[N]={0},num[N],rev[N]={0};
    LL mi(LL x,LL y,LL p){
        if (y==0) return 1LL;
        if (y==1) return x%p;
        LL mm=mi(x,y/2,p);
        if (y%2) return mm*mm%p*x%p;
        else return mm*mm%p;}
    bool judge(int x){
        for (int i=2;i*i<=m;++i)
            if ((m-1)%i==0&&mi((LL)x,(LL)(m-1)/i,m)==1) return false;
        return true;}
    int find(){
        int i;if (m==2) return 1;
        for (i=2;!judge(i);++i);
        return i;}
    void pre(){
        int i,j,k,g;
        for (up=1,l=0;up<2*m;up<<=1,++l);up<<=1;++l;
        for (i=0;i<up;++i){
            for (k=0,j=i;j;j>>=1) po[++k]=j&1;
            for (j=1;j<=l;++j) rev[i]=(rev[i]<<1)|po[j];
        }g=find();
        for (num[0]=1,po[1]=0,i=1;i<m-1;++i){
            num[i]=(int)((LL)num[i-1]*(LL)g%m);
            po[num[i]]=i;
        }nup=mi(up,P-2,P);}
    void ntt(LL *a,int f){
        int i,j,k;LL w,wn,x,y;
        for (i=0;i<up;++i) ai[i]=a[rev[i]];
        for (i=0;i<up;++i) a[i]=ai[i];
        for (i=2;i<=up;i<<=1){
            wn=mi(G,(f==1 ? (P-1)/i : P-1-(P-1)/i),P);
            for (j=0;j<up;j+=i)
                for (w=1LL,k=j;k<j+i/2;++k){
                    x=a[k]%P;y=w*a[k+i/2]%P;
                    a[k]=(x+y)%P;
                    a[k+i/2]=((x-y)%P+P)%P;
                    w=w*wn%P;
                }
        }if (f==-1) for (i=0;i<up;++i) a[i]=a[i]*nup%P;
    }
    void mul(LL *c,LL *a,LL *b){
        int i;
        for (i=0;i<up;++i) bi[i]=a[i];
        for (i=0;i<up;++i) ci[i]=b[i];
        ntt(bi,1),ntt(ci,1);
        for (i=0;i<up;++i) c[i]=bi[i]*ci[i]%P;
        for (ntt(c,-1),i=m-1;i<up;++i){
          c[i-m+1]=(c[i-m+1]+c[i])%P;c[i]=0LL;
        }
    }
    void pow(LL *a,int n){
        c[0]=1LL;
        while(n){
            if (n&1) mul(c,c,a);
            mul(a,a,a);
            n>>=1;}
    }
    int main(){
        int i,n,si,x;
        scanf("%d%d%d%d",&n,&m,&x,&si);
        for (i=1;i<=si;++i) scanf("%d",&s[i]);
        for (pre(),i=1;i<=si;++i){
            if (s[i]==0) continue;
            ++aa[po[s[i]]];
        }pow(aa,n);
        printf("%I64d
    ",c[po[x]]);
    }
    View Code

    day2T1

    题目大意:有n个敌人,m个武器,每种武器有特定的攻击敌人,伤害不同,求最短消灭所有敌人的时间。

    思路:因为有小数,我们乘一个1000000,到整数上,然后二分答案,跑网络流(每种武器在二分时间的最多的伤害已知,如果到汇点满流,就是可行)。

            注意longlong和int之间一些强转。。。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define inf 1000000
    #define linf 9223372036854775806LL
    using namespace std;
    struct use{
        int st,en;
        long long va;
    }edge[10000]={0};
    int a[100]={0},b[100]={0},tot,map[100][100],bb[100]={0},ba[100]={0},n,m,point[200]={0},next[10000]={0},
        gap[200]={0},cur[200]={0},dis[200]={0},pre[200]={0};
    void add(int st,int en,long long va)
    {
        ++tot;next[tot]=point[st];point[st]=tot;
        edge[tot].st=st;edge[tot].en=en;edge[tot].va=va;
        ++tot;next[tot]=point[en];point[en]=tot;
        edge[tot].st=en;edge[tot].en=st;edge[tot].va=0;
    }
    long long sap(int st,int en)
    {
        int i,j,u;
        long long minn,ans=0;
        bool f=false;
        memset(gap,0,sizeof(gap));
        memset(dis,0,sizeof(dis));
        memset(pre,0,sizeof(pre));
        gap[0]=en-st+1;u=st;
        for (i=st;i<=en;++i) cur[i]=point[i];
        while(dis[st]<en-st+1)
        {
            f=false;
            for (i=cur[u];i;i=next[i])
            {
                if (edge[i].va&&dis[edge[i].en]+1==dis[u])
                {
                    f=true;cur[u]=i;break;
                }
            }
            if (f)
            {
                pre[edge[i].en]=i;u=edge[i].en;
                if (u==en)
                {
                    minn=linf;
                    for (i=en;i!=st;i=edge[pre[i]].st)
                        minn=min(minn,edge[pre[i]].va);
                    ans+=minn;
                    for (i=en;i!=st;i=edge[pre[i]].st)
                    {
                        edge[pre[i]].va-=minn;
                        edge[pre[i]^1].va+=minn;
                    }
                    u=st;
                }
            }
            else
            {
                --gap[dis[u]];
                if (!gap[dis[u]]) return ans;
                minn=en-st+1;
                for (i=point[u];i;i=next[i])
                  if (edge[i].va&&dis[edge[i].en]<minn) minn=dis[edge[i].en];
                cur[u]=point[u];
                dis[u]=minn+1;++gap[dis[u]];
                if (u!=st) u=edge[pre[u]].st;
            }
        }
        return ans;
    }
    bool judge(long long tim,int en)
    {
        int i,j;
        long long sum=0,k;
        tot=1;
        memset(point,0,sizeof(point));
        memset(next,0,sizeof(next));
        for (i=1;i<=m;++i)
            add(1,bb[i],tim*(long long)b[i]);
        for (i=1;i<=m;++i)
          for (j=1;j<=n;++j)
              if (map[i][j]) add(bb[i],ba[j],linf);
        for (j=1;j<=n;++j)
        {
          add(ba[j],en,(long long)inf*(long long)a[j]);
          sum+=(long long)inf*(long long)a[j];
        }
        k=sap(1,en);
        if (k==sum) return true;
        else return false;
    }
    int main()
    {
        int i,j,sum=0,minn,en;
        long long ll,rr,mid;
        double ans;
        scanf("%d%d",&n,&m);
        for (i=1;i<=n;++i) 
        {
           scanf("%d",&a[i]);
           sum+=a[i];
           ba[i]=m+i+1;
        }
        minn=2100000000;
        for (j=1;j<=m;++j) 
        {
            scanf("%d",&b[j]);
            minn=min(minn,b[j]);
            bb[j]=j+1;
        }
        en=2+m+n;
        for (i=1;i<=m;++i)
          for (j=1;j<=n;++j)
            scanf("%d",&map[i][j]);
        ll=0;rr=(long long)(sum/minn)*(long long)inf;
        while(ll<rr)
        {
            mid=(ll+rr)/2;
            if (judge(mid,en)) rr=mid;
            else ll=mid+1;
        }
        ans=ll*1.0/inf;
        printf("%.6f
    ",ans);
    }
    View Code

    day2T2

    题目大意:设d(x)表示x的约数个数,求sigma(i=1~n)sigma(j=1~m)d(ij)

    思路:d(ij)=sigma(i|n)sigma(j|m)e(gcd(i,j))(考虑如果i、j不互质的时候可以通过质因数的变换使得互质,这样就导致多次计算了。)对这个式子反演。

      sigma(i=1~n)sigma(j=1~m)d(ij)=sigma(i=1~n)sigma(j=1~m)(n/i)(m/j)e(gcd(i,j))

                       =sigma(i=1~n)sigma(j=1~m)(n/i)(m/j)sigma(d|i&&d|j)mu(d)

                       =sigma(d=1~min(n,m))mu(d)gi(n/d)gi(m/d)      (gi(x)=sigma(i=1~x)(x/i),这一步可以设i=k1gcd(),j=k2gcd()                                                                                                                          考虑)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxm 50005
    #define LL long long
    using namespace std;
    int prime[maxm]={0},mu[maxm]={0};
    LL gi[maxm]={0};
    bool flag[maxm]={0};
    void shai(int n){
        int i,j;mu[1]=1;
        for (i=2;i<=n;++i){
            if (!flag[i]){prime[++prime[0]]=i;mu[i]=-1;}
            for (j=1;j<=prime[0]&&prime[j]*i<=n;++j){
                flag[prime[j]*i]=true;
                if (i%prime[j]) mu[i*prime[j]]=-mu[i];
                else{mu[i*prime[j]]=0;break;}
            }
        }for (i=2;i<=n;++i) mu[i]+=mu[i-1];
    }
    void pre(int n){
        int i,j,la;
        for (i=1;i<=n;++i)
            for (j=1;j<=i;j=la+1){
                la=i/(i/j);gi[i]+=(LL)(i/j)*(LL)(la-j+1);
            }
    }
    LL calc(int n,int m){
        int i,j,la;LL ans=0;
        if (n>m) swap(n,m);
        for (i=1;i<=n;i=la+1){
            la=min(n/(n/i),m/(m/i));
            ans+=(LL)(mu[la]-mu[i-1])*gi[n/i]*gi[m/i];
        }return ans;
    }
    int main(){
        int t,n,m;
        shai(maxm-1);pre(maxm-1);
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            printf("%I64d
    ",calc(n,m));
        }
    }
    View Code

    dayT3

    题目大意:一个2行n列的网格,格上有边权,两种操作:修改某一条边权;查询l~r两行的最小生成树的权值。

    思路:对于一个格子(包含四个点)有5种状态(本来是10种,但有一些在转移时是一样的,所以放在一起做;这5种分别是:左右两列都需要在外面相接,左或右任意一个或者必选哪个,格已经连通,然后相应的有17种转移)。注意:格已连通的时候有四种初始,四条边分别去掉的情况都可以。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    #define N 60005
    #define inf 2100000000LL
    using namespace std;
    struct use{
        LL vi[5];
        void init(){for (int i=0;i<5;++i) vi[i]=inf;}
    }tr[N*4];
    LL ed[3][N];
    int map[5][5]={{-1,0,0,-1,3},
                   {0,1,2,3,4},
                   {-1,2,2,-1,4},
                   {0,3,-1,3,-1},
                   {2,4,-1,4,-1}};
    char in(){
        char ch=getchar();
        while(ch<'A'||ch>'Z') ch=getchar();
        return ch;}
    void paint(int i,int x){
        tr[i].init();
        tr[i].vi[0]=min(ed[0][x],ed[1][x]);
        tr[i].vi[1]=ed[0][x]+ed[1][x];
        tr[i].vi[2]=min(ed[0][x],ed[1][x])+ed[2][x];
        tr[i].vi[3]=min(ed[0][x],ed[1][x])+ed[2][x+1];
        tr[i].vi[4]=min(ed[0][x]+ed[1][x]+min(ed[2][x],ed[2][x+1]),
                    ed[2][x]+ed[2][x+1]+min(ed[0][x],ed[1][x]));}
    use updata(use x,use y){
        use c;c.init();int i,j;
        for (i=0;i<5;++i)
          for (j=0;j<5;++j){
              if (map[i][j]<0) continue;
              c.vi[map[i][j]]=min(c.vi[map[i][j]],x.vi[i]+y.vi[j]);
          }return c;}
    void build(int i,int l,int r){
        if (l==r){paint(i,l);return;}
        int mid=l+r>>1;
        build(i<<1,l,mid);build(i<<1|1,mid+1,r);
        tr[i]=updata(tr[i<<1],tr[i<<1|1]);}
    use ask(int i,int l,int r,int ll,int rr){
        if (ll<=l&&r<=rr) return tr[i];
        int mid=l+r>>1;use x1,x2;
        bool f1,f2;f1=f2=false;
        if (ll<=mid){f1=true;x1=ask(i<<1,l,mid,ll,rr);}
        if (rr>mid){f2=true;x2=ask(i<<1|1,mid+1,r,ll,rr);}
        if (!f1) return x2;
        if (!f2) return x1;
        return updata(x1,x2);}
    void tch(int i,int l,int r,int x){
        if (l==r){paint(i,l);return;}
        int mid=l+r>>1;
        if (x<=mid) tch(i<<1,l,mid,x);
        else tch(i<<1|1,mid+1,r,x);
        tr[i]=updata(tr[i<<1],tr[i<<1|1]);}
    int main(){
        int n,m,i,j,x0,y0,x1,y1;LL w;scanf("%d%d",&n,&m);
        for (i=1;i<n;++i) scanf("%I64d",&ed[0][i]);
        for (i=1;i<n;++i) scanf("%I64d",&ed[1][i]);
        for (i=1;i<=n;++i) scanf("%I64d",&ed[2][i]);
        --n;build(1,1,n);
        for (i=1;i<=m;++i){
            char ch=in();
            if (ch=='Q'){
                scanf("%d%d",&y0,&y1);
                if (y1<y0) swap(y0,y1);
                if (y0==y1) printf("%I64d
    ",ed[2][y0]);
                else{
                    use xx=ask(1,1,n,y0,y1-1);
                    printf("%I64d
    ",xx.vi[4]);
                }
            }else{
                scanf("%d%d%d%d%I64d",&x0,&y0,&x1,&y1,&w);
                if (x0==x1){
                    if (y0>y1) swap(y0,y1);
                    ed[x0-1][y0]=w;
                    tch(1,1,n,y0);
                }else{
                    ed[2][y0]=w;
                    if (y0>1) tch(1,1,n,y0-1);
                    if (y0<=n) tch(1,1,n,y0);
                }
            }
        }
    }
    View Code
  • 相关阅读:
    史上最详细 Linux 用户与用户组知识
    MySQL -2- 体系结构--随笔小记
    MySQL -2- 体系结构
    MySQL -1- 简介及安装
    MySQL -0- 课程大纲及课程链接
    探索Windows命令行系列(4):通过命令操作文件和文件夹
    探索Windows命令行系列(3):命令行脚本基础
    探索Windows命令行系列(2):命令行工具入门
    探索Windows命令行系列(1):导航目录
    Oracle 分页方法研究
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4445298.html
Copyright © 2020-2023  润新知