无题2

题解

第一题:水

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


const int M = 1e5 + 5;

struct Node{
    int s, t;
}p[M];
bool cmp(Node A, Node B){
    return A.t > B.t;
}
int main(){
    freopen("manage.in","r",stdin);
    freopen("manage.out","w",stdout);
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)scanf("%d%d", &p[i].s, &p[i].t);
    sort(p + 1, p + 1 + n, cmp);
    int now = p[1].t;
    p[n + 1].t = 1e9;
    for(int i = 1; i <= n; i++){
        now -= p[i].s;
        if(now > p[i + 1].t) now = p[i + 1].t;
    }
    printf("%d
", now >= 0 ? now : -1);
}
View Code

第二题:先tarjan缩点,然后树上背包;我用的带权并查集,跑的分组背包,忽略了分叉的情况;

#include<bits/stdc++.h>
using namespace std;
const int M = 1e5 + 10;

int v[M], w[M], V[M], W[M], fa[M], dp[305][M], idx, scc;
int tot, place[M], h[M], dfn[M], low[M], d[M], siz[M], du[M]; 
bool ins[M];
struct edge{
    int v, nxt;
}G[M];
void add(int u, int v){
    G[++tot].nxt = h[u]; G[tot].v = v; h[u] = tot;
}

vector <int> group[M];
stack <int> t;
void tarjan(int u){
    dfn[u] = low[u] = ++idx;
    t.push(u); ins[u] = 1;
    
    int v = d[u];
    if(v){
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(ins[v]) low[u] = min(low[u], dfn[v]);
    }
    
    
    if(low[u] == dfn[u]){
        scc++;
        while(1){
            int st = t.top(); t.pop();
            place[st] = scc;
            ins[st] = 0;
            if(st == u)break;
        }
    }
}
int n, m;
void dfs(int u){
    dp[u][W[u]] = V[u];
    for(int i = h[u]; i; i = G[i].nxt){
        int v = G[i].v;
        dfs(v);
        for(int vv = m; vv >= W[u]; vv--)
            for(int p = 0; p <= vv; p++)
                if(dp[u][vv - p] >= 0 && dp[v][p] >= 0)
                    dp[u][vv] = max(dp[u][vv], dp[u][vv - p] + dp[v][p]);
    }
    
    
}


int main(){
    freopen("software.in","r",stdin);
    freopen("software.out","w",stdout);
    
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &w[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &v[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &d[i]);
        
    for(int i = 1; i <= n; i++)
        if(!dfn[i]) tarjan(i);
    for(int i = 1; i <= n; i++){
        int u = place[i];
        V[u] += v[i]; W[u] += w[i];
        if(place[d[i]] != place[i])
            add(place[d[i]], place[i]), du[place[i]]++;
    }
    for(int i = 1; i <= scc; i++)
        if(!du[i])add(0, i);
    memset(dp, 0x8f, sizeof(dp));
    dfs(0);
    int ans = 0;
    for(int i = 0; i <= m; i++)ans = max(ans, dp[0][i]);
     printf("%d
", ans);
           
    
    
    
} 
View Code

第三题:线段统计区间中递增的数, modify的神奇操作;

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 5;
int n,val,pos,m;

struct nd {    
    double val;
    int ans;
}f[4 * N];

int calc(int o,int l,int r,double val) {
    
    if(l == r) return f[o].val - val >= 1e-10;
    int mid = (l + r) >> 1;
    if(f[2 * o].val - val <= 1e-10) {
        return calc(2 * o + 1,mid + 1,r,val);
    }
    else {
        return f[o].ans - f[2 * o].ans + calc(2 * o,l,mid,val);
    }
}

void modify(int o,int l,int r,int pos,double val) {
    
    if(l == r) {
        f[o].val = val;
        f[o].ans = 1;
        return ;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) modify(2 * o,l,mid,pos,val);
    else modify(2 * o + 1,mid + 1,r,pos,val);
    f[o].val = max(f[2 * o].val,f[2 * o + 1].val);
    f[o].ans = f[2 * o].ans + calc(2 * o + 1,mid + 1,r,f[2 * o].val);
}

int main( ) {
    freopen("rebuild.in","r",stdin);
    freopen("rebuild.out","w",stdout);
    scanf("%d%d",& n,& m);
    while(m --) {
        scanf("%d%d",& pos,& val);
        modify(1,1,n,pos,1.0*val/pos);
        printf("%d
", f[1].ans);
    }
}
View Code
原文地址:https://www.cnblogs.com/EdSheeran/p/9648570.html