zoukankan      html  css  js  c++  java
  • CCPC-Winter Camp div2 day5

    DIV2

    有部分div1的题会写

    div1的大佬真的太强了

    向他们学习

    (好像和zqc大佬说过话了hhh,zqc大佬真的是一个超有意思的人啊,羡慕有妹子队友的zqc大佬)

    A:

    你有一棵树,你想把它画在平面上,使得没有边相交。

    题解:dfs(u,dep)表示我在第dep层,第cnt[dep]列来放置第u个节点

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+5;
    int n,m;
    struct EDGE{
        int v,nxt;
    }edge[maxn];
    int head[maxn];
    int tot=0;
    void add_edge(int u,int v){
        edge[tot].v=v;
        edge[tot].nxt=head[u];
        head[u]=tot++;
    }
    int cnt[maxn];
    int vis[maxn];
    struct node{
        int x,y;
    }ans[maxn];
    
    void dfs(int u,int dep){
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].v;
            if(!vis[v]){
                vis[v]=1;
                ans[v].x=dep;
                ans[v].y=cnt[dep];
                cnt[dep]++;
                dfs(v,dep-1);
            }
        }
    }
    int main(){
    
        memset(head,-1,sizeof(head));
        tot=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        for(int i=1;i<=n;i++){
            cnt[i]=1;
            vis[i]=0;
        }
        dfs(1,n);
        for(int i=1;i<=n;i++){
            printf("%d %d
    ",ans[i].x,ans[i].y);
        }
    }
    View Code

    B:

    所有n个节点有标号的无根树,直径为0,1,,n1的树有多少个。

    由于答案很大,对mod取模。

    学了一点新知识:purfer序列又和其他神奇的序列一样,我都不会QAQ(晚风为什么这么凉,教练我想学数学

     purfer序列是用来对无根数计数的 ,(大概是无根树的同构balabala的太多了,然后某神奇的科学家就给整出这个序列了)

    日后补这个知识点(flag立下了

    C:

    你有一个数列。你可以进行这样的一次操作,每次选择数列中其中一个数然后将其除2下取整请问对这些数字进行不超过kk次操作,这些数字的总和最小值可能是多少。’

    div2的n只有1e3,虽然说k是1e9,但是非常显然对于每一个ai都最多操作30次即可,复杂度是30*nlogn

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 5;
    int a[maxn];
    priority_queue<int> q;
    int n, k;
    int main() {
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            q.push(a[i]);
        }
        while(k--) {
            if(q.top() / 2 == 0) break;
            int x = q.top();
            q.pop();
            q.push(x / 2);
        }
        long long ans = 0;
        while(!q.empty()) {
            ans += q.top();
            q.pop();
        }
        cout << ans << endl;
    }
    View Code

    div1的版本有点难,最主要的是他是询问这个区间内进行k 次操作后最小的区间和

    这些天camp学到一个知识点叫做拆分,就是把一个数用二进制分组的形式表示,这样一个数最多就可以被表示成log(ai)个数,我们预处理出这n个数拆出来的数,即n*log(n)个数,用主席数维护区间前k大数,所以每次询问得到这个区间前k大和,用区间和减去即可得到k次操作后最小的区间和

    但是!!!重点来了,我们计算一下空间复杂度。n*log(a[i])*log(segma(log(a[i]))),被256M卡成弟弟的空间复杂度,所以你没了

    不过可爱的dls小姐姐告诉我们,

    emmm貌似是用重构主席树,然后离线操作,这样复杂度就被滚了一个log下去

    代码如下

    #include <set>
    #include <map>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <ctime>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    typedef pair<LL, LL> pLL;
    typedef pair<LL, int> pLi;
    typedef pair<int, LL> pil;;
    typedef pair<int, int> pii;
    typedef unsigned long long uLL;
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    #define bug printf("*********
    ")
    #define FIN freopen("input.txt","r",stdin);
    #define FON freopen("output.txt","w+",stdout);
    #define IO ios::sync_with_stdio(false),cin.tie(0)
    #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]
    "
    #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]
    "
    #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]
    "
    
    const double eps = 1e-8;
    const int mod = 1000000007;
    const int maxn = 2e5 + 5;
    const double pi = acos(-1);
    const int INF = 0x3f3f3f3f;
    const LL INFLL = 0x3f3f3f3f3f3f3f3f;
    struct TREE {
        int ls, rs, s;
        LL sum;
    } T[maxn << 5];
    int tot = 0;
    struct QUERY {
        int l, r, k;
        LL ans;
    } q[maxn << 2];
    LL read() {
        int x = 0, 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();
        }
        return x * f;
    }
    
    void push_up(int rt) {
        int ls = T[rt].ls;
        int rs = T[rt].rs;
        T[rt].s = T[ls].s + T[rs].s;
        T[rt].sum = T[ls].sum + T[rs].sum;
        return;
    }
    void update(int l, int r, int &rt, int pre, int x) {
        rt = ++tot;
        T[rt] = T[pre];
        if(l == r) {
            T[rt].s++;
            T[rt].sum += (x - (x >> 1));
            return;
        }
        int mid = (l + r) >> 1;
        if(x <= mid) update(l, mid, T[rt].ls, T[pre].ls, x);
        else update(mid + 1, r, T[rt].rs, T[pre].rs, x);
        push_up(rt);
    }
    LL query(int l, int r, int rt, int pre, int k) {
        if(l == r) return (LL)(k * (l - (l >> 1)));
        int ls = T[rt].ls;
        int rs = T[rt].rs;
        int Ls = T[pre].ls;
        int Rs = T[pre].rs;
        int mid = (l + r) >> 1;
        LL ans = 0;
        if(k > T[rs].s - T[Rs].s) {
            ans += T[rs].sum - T[Rs].sum;
            ans += query(l, mid, ls, Ls, k - (T[rs].s - T[Rs].s)) ;
        } else {
            ans += query(mid + 1, r, rs, Rs, k);
        }
        return ans;
    }
    LL sum[maxn];
    int  root[maxn];
    LL a[maxn];
    int num[maxn];
    int main() {
    #ifndef ONLINE_JUDGE
        FIN
    #endif
        int n, m;
        sum[0] = 0;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) {
            a[i] = read();
            sum[i] = sum[i - 1] + a[i];
        }
    
        for(int i = 1; i <= m; i++) {
            q[i].l = read();
            q[i].r = read();
            q[i].k = read();
            q[i].ans = sum[q[i].r] - sum[--q[i].l];
        }
    
        for (int i = 29; i >= 0; --i) {
            int L = 1 << i, R = 2 << i;
            //二进制分组
            tot = 0;//重构
            for (int j = 1; j <= n; ++j) {
                if ((a[j] >> i) & 1) {
                    update(L, R, root[j], root[j - 1], a[j]);
                    sum[j] = sum[j - 1] + a[j] - (a[j] >> 1);
                    num[j] = num[j - 1] + 1;
                } else {
                    root[j] = root[j - 1];
                    sum[j] = sum[j - 1];
                    num[j] = num[j - 1];
                }
            }
            for (int j = 1; j <= m; ++j) {
                if (q[j].k && q[j].k >= num[q[j].r] - num[q[j].l]) {
                    q[j].k -= num[q[j].r] - num[q[j].l];
                    q[j].ans -= sum[q[j].r] - sum[q[j].l];
                } else {
                    q[j].ans -= query(L, R, root[q[j].r], root[q[j].l], q[j].k);
                    q[j].k = 0;
                }
            }
            for (int j = 1; j <= n; ++j) if ((a[j] >> i) & 1) a[j] >>= 1;
        }
        for(int i = 1; i <= m; i++) {
            printf("%lld
    ", q[i].ans);
        }
        return 0;
    }
    View Code

    D:

    你有一个n*n的矩阵,一开始都是空的,你要在其中填入1n2的数字和字符X

    要求每行每列中1n-2中的每个数都恰好出现了一次,并且恰好有两个字符X

    同时对于第i行,要求两个X之间的数字之和为ri,第i列,要求两个X之间的数字之和为ci

     n小于7

    大搜索,把所有情况搜出来即可

    剪枝1:由于每行每列的和是有限制的,我们维护一个第i行的和sum1和第j列的和sun2,如果sum1、sum2大于这个限制,直接return 即可,(要考虑X是否放了两个的情况)

    剪枝2:预处理出加到每行的和可以用哪些数得到,还有每列的和可以用哪些数得到,然后用这些数去枚举暴力,就可以跑出答案(听说dls0ms过了,神仙)

    自己没有补(flag++)

    队友代码:

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define iis std::ios::sync_with_stdio(false)
    #define pb push_back
    #define o2(x) (x)*(x)
    using namespace std;
    typedef long long LL;
    typedef pair<int, LL> pii;
    const int  MXN = 2e6 + 6;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    int n;
    int vis[15][15];
    int visr[15][15];
    int visc[15][15];
    int needr[15];
    int needc[15];
    int nowrx[15],nowcx[15];// di  i 行 第一个x的纵坐标  竖 横坐标
    int haverx[15],havecx[15];
    int nowc[15],nowr[15];
    int totc[15],totr[15];
    int flag = 0;
    int sum;
    bool check() {
        for(int i=1; i<=n; i++) {
            if(havecx[i]!=2 || haverx[i]!=2) {
                return 0;
            }
        }
        return 1;
    }
    void dfs(int x,int y) {
        //cout<<"now:"<<x<<","<<y<<",,"<<flag<<endl;
        if(haverx[x]==0 && sum-totr[x]<needr[x]) return;
        if(havecx[y]==0 && sum-totc[y]<needc[y]) return;
        if(flag ) return ;
        if(x==n+1) {
            if(check())
                flag = 1;
            //cout<<"haha:"<<flag<<endl;
            for(int i=1; i<=n; i++) {
                for(int j=1; j<=n; j++) {
                    if(vis[i][j]!=-1) {
                        printf("%d",vis[i][j]);
                    } else {
                        printf("X");
                    }
                }
                puts("");
            }
            return ;
        }
    //    for(int i=1; i<=n; i++) {
    //        for(int j=1; j<=n; j++) {
    //            if(vis[i][j]!=-1) {
    //                printf("%d",vis[i][j]);
    //            } else {
    //                printf("X");
    //            }
    //        }
    //        puts("");
    //    }
        // 判断是否可放x
        if(haverx[x]==0 &&havecx[y]==0) {
            nowrx[x]=y;
            nowcx[y]=x;
            havecx[y]++;
            haverx[x]++;
            vis[x][y]=-1;
            if(y+1>n) {
                if(haverx[x]==2)
                    dfs(x+1,1);
            } else {
                dfs(x,y+1);
            }
            vis[x][y]=0;
            nowrx[x]=0;
            nowcx[y]=0;
            havecx[y]--;
            haverx[x]--;
        }
        // 横有了一个x 竖没有x
        else if(haverx[x]==1 && havecx[y]==0) {
            int cnt = nowr[x];//getnum(nowrx[x],y,x,1);
            //cout<<"cnt:"<<cnt<<endl;
            // 第 i 行 两个x之间的属的和满足ri
            if(cnt==needr[x]) {
                havecx[y]++;
                haverx[x]++;
                nowcx[y]=x;
                vis[x][y]=-1;
                if(y+1>n) {
                    if(haverx[x]==2)
                        dfs(x+1,1);
                } else {
                    dfs(x,y+1);
                }
                vis[x][y]=0;
                havecx[y]--;
                haverx[x]--;
                nowcx[y]=0;
            }
        }
        // 竖有了一个x 横没有x
        else if(haverx[x]==0 && havecx[y]==1) {
            int cnt = nowc[y];//getnum(nowcx[y],x,y,0);
            // 第 i 行 两个x之间的属的和满足ri
            if(cnt==needc[y]) {
                havecx[y]++;
                haverx[x]++;
                nowrx[x]=y;
                vis[x][y]=-1;
                if(y+1>n) {
                    if(haverx[x]==2)
                        dfs(x+1,1);
                } else {
                    dfs(x,y+1);
                }
                vis[x][y]=0;
                havecx[y]--;
                haverx[x]--;
                nowrx[x]=0;
            }
        }// 横竖都有一个
        else {
            int cnt1 = nowr[x];//getnum(nowrx[x],y,x,1);
            int cnt2 = nowc[y];//getnum(nowcx[y],x,y,0);
            if(cnt1 == needr[x] && cnt2 == needc[y]) {
                havecx[y]++;
                haverx[x]++;
                vis[x][y]=-1;
                if(y+1>n) {
                    if(haverx[x]==2)
                        dfs(x+1,1);
                } else {
                    dfs(x,y+1);
                }
                vis[x][y]=0;
                havecx[y]--;
                haverx[x]--;
            }
        }
        for(int i=1; i<=n-2; i++) {
            int cnt1 = 0;
            if(haverx[x]==1) {
                cnt1 =nowr[x];//getnum(nowrx[x],y,x,1);
    
                if(cnt1+i>needr[x]) continue;
                //cout<<"cnt1+i:"<<cnt1+i<<"vs"<<needr[x]<<endl;
            }
            int cnt2 = 0;
            if(havecx[y]==1) {
                cnt2 = nowc[y];//getnum(nowcx[y],x,y,0);
                if(cnt2+i>needc[y]) continue;
            }
            if(visc[y][i]==0 && visr[x][i]==0 ) {
                visc[y][i]=1;
                visr[x][i]=1;
                vis[x][y]=i;
                totc[y]+=i;
                totr[x]+=i;
                if(haverx[x]==1) {
                    nowr[x]+=i;
                }
                if(havecx[y]==1) {
                    nowc[y]+=i;
                }
                if(y+1>n) {
                    if(haverx[x]==2)
                        dfs(x+1,1);
                } else {
                    dfs(x,y+1);
                }
                if(haverx[x]==1) {
                    nowr[x]-=i;
                }
                if(havecx[y]==1) {
                    nowc[y]-=i;
                }
                totc[y]-=i;
                totr[x]-=i;
                visc[y][i]=0;
                visr[x][i]=0;
                vis[x][y]=0;
            }
        }
    }
    void init() {
        flag = 0;
        memset(vis,0,sizeof vis);
        memset(visr,0,sizeof visr);
        memset(visc,0,sizeof visc);
        memset(needr,0,sizeof needr);
        memset(needc,0,sizeof needc);
        memset(nowrx,0,sizeof nowrx);
        memset(nowcx,0,sizeof nowcx);
        memset(haverx,0,sizeof haverx);
        memset(havecx,0,sizeof havecx);
        memset(nowc,0,sizeof nowc);
        memset(nowr,0,sizeof nowr);
        memset(totc,0,sizeof totc);
        memset(totr,0,sizeof totr);
        sum=0;
        for(int i=1; i<=n-2; i++) {
            sum+=i;
        }
    //    cout<<sum<<endl;
    }
    int main() {
        int T;
        scanf("%d",&T);
        while(T--) {
    
            scanf("%d",&n);
            init();
            for(int i=1; i<=n; i++) {
                scanf("%d",&needr[i]);
            }
            for(int j=1; j<=n; j++) {
                scanf("%d",&needc[j]);
            }
            dfs(1,1);
            if(T)
                puts("");
        }
    }
    View Code

    E:(待补)

    F:

    n<=15非常明显的状压dp

    状压dp计数,定义状态为dp[i][j][k] ,长度为i到最后一个数是j的状态k的排列的数量

    枚举时判断一下如果这个数放进去是否符合题目的序列即可

    最后的答案就是长度为n的序列结尾数从1~n,状态为(1<<n)-1 时的和

    #include<bits/stdc++.h>
    using namespace std;
    const int mod = 1e9 + 7;
    int n;
    char str[20];
    int dp[16][16][1 << 16]; //长度为i,结尾是j,状态是k
    int main() {
        memset(dp, 0, sizeof(dp));
        scanf("%d %s", &n, str + 1);
        for(int i = 1; i <= n; i++) {
            dp[1][i][(1 << i - 1)] = 1;
        }
        for(int i = 1; i < n; i++) {
            for(int j = 1; j <= n; j++) {
                for(int k = 1; k <= n; k++) {
                    if(j != k) {
                        int flag = 0;
                        if(((j % k == 0 && j / k == 2) || (k % j == 0 && k / j == 2)) ) {
                            if(str[i] == '1') {
                                flag = 1;
                            }
                        } else {
                            if(str[i] == '0') {
                                flag = 1;
                            }
                        }
                        //cout<<flag<<endl;
                        if(flag) {
                            for(int p = 0; p < (1 << n); p++) {
                                if((p & (1 << k - 1)) == 0) {
                                    dp[i + 1][k][p | (1 << k - 1)] = (dp[i + 1][k][p | (1 << k - 1)] + dp[i][j][p]) % mod;
                                }
                            }
                        }
                    }
                }
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
            ans = (ans + dp[n][i][(1 << n) - 1]) % mod;
        cout << ans << endl;
    }
    View Code

     G:

    数论知识,待补(目测不可做)(真的不可做)(不补了告辞)(可以留着祸害学弟)(去py一下标程)

    H:

    题意:

    div1是非常不快乐的树链剖分,div2是非常快乐的dfs

     注意建图,因为最多复制m边,那么最多也就只有1e6条边,直接建就行,然后dfs计数,点对之间的距离就是左侧树的大小*右侧树的大小,算贡献

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 5;
    const int mod = 1e9 + 7;
    struct EDGE {
        int v, nxt;
    } edge[maxn << 2];
    int head[maxn];
    int tot;
    void add_edge(int u, int v) {
        edge[tot].v = v;
        edge[tot].nxt = head[u];
        head[u] = tot++;
    }
    long long ans = 0;
    long long sz[maxn];
    int n, m, u, v, a, b;
    void dfs(int u, int pre) {
        sz[u] = 1;
        for(int i = head[u]; i != -1; i = edge[i].nxt) {
            int v = edge[i].v;
            if(v == pre) continue;
            dfs(v, u);
            sz[u] += sz[v];ji
            ans = (ans % mod + (long long)sz[v] * (n * m - sz[v]) % mod) % mod;
        }
    }
    int main() {
        memset(head, -1, sizeof(head));
        tot = 0;
        scanf("%d%d", &n, &m);
        for(int i = 1; i < n; i++) {
            scanf("%d%d", &u, &v);
            for(int j = 0; j < m; j++) {
                add_edge(u + j * n, v + j * n);
                add_edge(v + j * n, u + j * n);
            }
        }
        for(int i = 1; i < m; i++) {
            scanf("%d%d%d%d", &a, &b, &u, &v);
            add_edge(u + (a - 1) * n, v + (b - 1) * n);
            add_edge(v + (b - 1) * n, u + (a - 1) * n);
        }
        dfs(1, 0);
        cout << ans << endl;
    }
    View Code

     I:

    题意:

    比赛最后开的这题,口胡了一大半,但是没有写出来,,,码力太差QAQ

    实际上真正写还是差一点的

    后来可爱的dls讲了之后再加上学长的帮助后终于会写了(感谢帅气的学长(舔狗舔到最后应有尽有

    题解:我们注意到x实际上是不变的,那么,我们每个数无论是怎么根据x排序,他的相对位置是不变的,这样我们就可以用前缀和来维护这个区间和

       注意大小关系,那么我们定义一个标记,如果这个数字小于等于x,那么这个数所在的位置的标记为0,否则为1,那么我们只需要用线段树维护区间内0和1的个数

       每次操作2的时候,我们只需要统计这个区间内0的个数,将区间(l,l+cnt0-1)给直接覆盖为0,剩下的(l+cnt0,r)覆盖为1

       每次操作3的时候,我们同理,统计区间内1的个数,然后覆盖即可

       每次操作1的时候,我们分别统计区间(1,l-1)(1,r)内0和1的个数,因为每个数字的相对位置是不变的,所以前缀和的相对位置也是不变的,直接减一减就行,具体看代码就懂啦

    代码:

    #include <set>
    #include <map>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <ctime>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    typedef pair<LL, LL> pLL;
    typedef pair<LL, int> pLi;
    typedef pair<int, LL> pil;;
    typedef pair<int, int> pii;
    typedef unsigned long long uLL;
    
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    #define FIN freopen("input.txt","r",stdin);
    #define IO ios::sync_with_stdio(false),cin.tie(0)
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    const double eps = 1e-8;
    const int mod = 1000000007;
    const int maxn = 2e5 + 7;
    const double pi = acos(-1);
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3fLL;
    int sum0[maxn<<2],sum1[maxn<<2],lazy[maxn<<2];
    LL a[maxn],q1[maxn],q2[maxn];
    int n,m,x;
    void push_up(int rt){
        sum0[rt]=sum0[rt<<1]+sum0[rt<<1|1];
        sum1[rt]=sum1[rt<<1]+sum1[rt<<1|1];
        return;
    }
    void push_down(int rt,int l,int r,int mid){
        if(lazy[rt]==-1) return;
        lazy[rt<<1]=lazy[rt];
        lazy[rt<<1|1]=lazy[rt];
        if(lazy[rt]==0){
            sum0[rt<<1]=(mid-l+1);
            sum0[rt<<1|1]=r-mid;
            sum1[rt<<1]=0;
            sum1[rt<<1|1]=0;
        }else{
            sum0[rt<<1]=0;
            sum0[rt<<1|1]=0;
            sum1[rt<<1]=mid-l+1;
            sum1[rt<<1|1]=r-mid;
        }
        lazy[rt]=-1;
        return;
    }
    void build(int l,int r,int rt){
        lazy[rt]=-1;
        if(l==r){
            //cout<<a[l]<<endl;
            if(a[l]<=x){
                sum0[rt]=1;
                sum1[rt]=0;
            }else{
                sum1[rt]=1;
                sum0[rt]=0;
            }
            return;
        }
        int mid=(l+r)>>1;
        build(lson);
        build(rson);
        push_up(rt);
    }
    
    void update(int L,int R,int flag,int l,int r,int rt){
        if(L>R) return;
        if(L<=l&&r<=R){
            if(flag==0){
                sum0[rt]=r-l+1;
                sum1[rt]=0;
            }else{
                sum1[rt]=r-l+1;     
                sum0[rt]=0;
            }
            lazy[rt]=flag;
            return;
        }
        int mid=(l+r)>>1;
        push_down(rt,l,r,mid);
        if(L<=mid) update(L,R,flag,lson);
        if(R>mid) update(L,R,flag,rson);
        push_up(rt);
    }
    int query(int L,int R,int flag,int l,int r,int rt){
        if(L>R) return 0;
        if(L<=l&&r<=R){
            if(flag==0){
                // debug(l);debug(r);
                // debug(rt);
                // debug(sum0[rt]);
                return sum0[rt];
            }else{
                return sum1[rt];
            }
        }
        int mid=(l+r)>>1;
        push_down(rt,l,r,mid);
        int ans=0;
        if(L<=mid) ans+=query(L,R,flag,lson);
        if(R>mid) ans+=query(L,R,flag,rson);
        return ans;
    }
    
    
    int main() {
    #ifndef ONLINE_JUDGE
        FIN
    #endif
        scanf("%d%d%d",&n,&m,&x);
        int tot1=0,tot2=0;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            if(a[i]<=x){
                tot1++;
                q1[tot1]=q1[tot1-1]+a[i];
            }else{
                tot2++;
                q2[tot2]=q2[tot2-1]+a[i];
            }
        }
        build(1,n,1);
        while(m--){
            int op,l,r;
            scanf("%d%d%d",&op,&l,&r);
            if(op==1){
                LL ans=0;
                int cnt1=query(1,l-1,0,1,n,1);
                int cnt2=query(1,r,0,1,n,1);
                // debug(cnt1);
                // debug(cnt2);
                ans+=q1[cnt2]-q1[cnt1];
                int cnt3=query(1,l-1,1,1,n,1);
                int cnt4=query(1,r,1,1,n,1);
                ans+=q2[cnt4]-q2[cnt3];
                cout<<ans<<endl;
            }else if(op==2){
                int cnt1=query(l,r,0,1,n,1);
               if(cnt1>0)
                update(l,l+cnt1-1,0,1,n,1);
                update(l+cnt1,r,1,1,n,1);
            }else{
                // debug(l);
                // debug(r);
                int cnt2=query(l,r,1,1,n,1);
                // debug(cnt2);
                if(cnt2>0)
                update(l,l+cnt2-1,1,1,n,1);
                update(l+cnt2,r,0,1,n,1);
            }
    
        }
        return 0;
    }
    View Code

    J:

    题解:

    只是端点相交不算相交,其余都算,那么上板子搞就行(T字形也算)

    #include<bits/stdc++.h>
    using namespace std;
    #define db double
    const int maxn = 1e5 + 5;
    const double eps = 1e-9;
    inline sign(double a) {
        return a < -eps ? -1 : a > eps;
    }
    inline int cmp(double a, double b) {
        return sign(a - b);
    }
    struct P {
        db x, y;
        P() {};
        P(db _x, db _y): x(_x), y(_y) {}
        P operator+(P p) {
            return {x + p.x, y + p.y};
        }
        P operator-(P p) {
            return {x - p.x, y - p.y};
        }
        db dot(P p) {
            return x * p.x + y * p.y;
        }
        db det(P p) {
            return x * p.y - y * p.x;
        }
    };
    #define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))
    #define cross0p(p1,p2,p3) sign(cross(p1,p2,p3))
    bool chkLL(P p1, P p2, P q1, P q2) { //直线平行
        double a1 = cross(q1, q2, p1);
        double a2 = -cross(q1, q2, p2);
        return sign(a1 + a2) != 0;
    }
    bool intersect(double l1, double r1, double l2, double r2) {
        if(l1 > r1) swap(l1, r1);
        if(l2 > r2) swap(l2, r2);
        return !(cmp(r1, l2) == -1 || cmp(r2, l1) == -1);
    }
    bool isSS(P p1, P p2, P q1, P q2) {
        return intersect(p1.x, p2.x, q1.x, q2.x) && intersect(p1.y, p2.y, q1.y, q2.y) &&
               cross0p(p1, p2, q1) * cross0p(p1, p2, q2) <= 0 && cross0p(q1, q2, p1)
               * cross0p(q1, q2, p2) <= 0;
    }
    double rad(P p1, P p2) {
        return atan2(p1.det(p2), p1.dot(p2));
    }
    bool xielv(P p1, P p2, P q1, P q2) {
        P p = p2 - p1;
        P q = q2 - q1;
        if(q.det(p) == 0 && cmp(rad(p, q), 0) == 0) return 1;
        return 0;
    }
    struct node {
        int u, v;
    } edge[maxn];
    int x[maxn];
    int y[maxn];
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &edge[i].u, &edge[i].v);
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &x[i], &y[i]);
        }
        int cnt = 0;
        for(int i = 1; i <= m; i++) {
            for(int j = i + 1; j <= m; j++) {
                P p1 = P{(double)x[edge[i].u], (double)y[edge[i].u]};
                P p2 = P{(double)x[edge[i].v], (double)y[edge[i].v]};
                P q1 = P{(double)x[edge[j].u], (double) y[edge[j].u]};
                P q2 = P{(double)x[edge[j].v], (double)y[edge[j].v]};
                if(isSS(p1, p2, q1, q2)) {
                    if(edge[i].u == edge[j].u || edge[i].u == edge[j].v || edge[i].v == edge[j].u || edge[i].v == edge[j].v) {
                        //printf("%lld %lld %lld %lld %lld %lld %lld %lld
    ", p1.x,p1.y,p2.x,p2.y,q1.x,q1.y,q2.x,q2.y);
                        if(edge[i].u == edge[j].u && xielv(p1, p2, q1, q2)) cnt++;
                        if(edge[i].u == edge[j].v && xielv(p1, p2, q2, q1)) cnt++;
                        if(edge[i].v == edge[j].u && xielv(p2, p1, q1, q2)) cnt++;
                        if(edge[i].v == edge[j].v && xielv(p2, p1, q2, q1)) cnt++;
                    } else cnt++;
                }
            }
        }
        cout << cnt << endl;
    }
    View Code
    每一个不曾刷题的日子 都是对生命的辜负 从弱小到强大,需要一段时间的沉淀,就是现在了 ~buerdepepeqi
  • 相关阅读:
    Java正則表達式入门
    Effect of Switchovers, Failovers, and Control File Creation on Backups
    Android 屏幕截图(底层实现方式)
    Java实现奇偶数排序
    Java实现奇偶数排序
    Java实现奇偶数排序
    Java实现找零问题
    Java实现找零问题
    Java实现找零问题
    Java实现找零问题
  • 原文地址:https://www.cnblogs.com/buerdepepeqi/p/10321806.html
Copyright © 2011-2022 走看看