Jeanny
寂兮,寥兮,独立不改,周行而不殆

C.Triple Attack

一句话题意:
n个敌人,你去攻击它。当你不是3的倍数,攻击力是1,敌人下降1,当你是3的倍数,敌人下降3.
\(a_i <= 10^9\)
\(n<=10^5\)

Analysis:
又是一道周期问题的题目。
所以需要想到5是一个周期,“1,1,3”是一组,然后这一组的开头和结尾是不完整的周期。

#include<bitsstdc++.h>
#define int long long 
using namespace std;
int n, last, x, cnt, fl;
signed main(){
    cin>>n;
    for(int i = 1; i <= n; i++){// 6 11 7
        cin>>x; fl = 0;
        if(last){
//            cout<<"iii: "<<i<<" "<<last<<endl;
            if(x >= 5 - last){
                cnt += (5 - last == 4 ? 2: 1);
                x -= (5 - last);
            }       
            else{
                if(last == 1){
                    if(x == 1){
                    	//1
                    	//1 3 -> 2 3 4
                        cnt += 1;
                        last = 2;
                    }
                    else {
                    	//1
                    	//1 3 -> 2 3 4
                        cnt += 2;
                        last = 0;
                    }
                }
                else if(last == 2){
                	// 1 1
                	// 3 -> 1 2 3 
                    cnt += 1;
                    last = 0;
                }
				fl = 1;
            }  
        } 
//		cout<<"teshu: "<<cnt<<endl;
        if(fl == 1) continue;
        cnt += x / 5 * 3;
        last = x % 5; //整数周期后,留的尾巴,从第一个周期开始 
        if(last == 1){// 1 
            cnt += 1;
        }
        else if(last == 2){
            cnt += 2;
        }
        else if(last == 3 || last == 4){
            cnt += 3;
            last = 0;
        }   
        // cout<<"cnt: "<<cnt<<endl;
//        cnt = 0;
    }
    cout<<cnt<<endl;
    return 0;
}
/*
1 1 3 1  6
1 3      2
1 1      2

3
6 11 7
1 1 3 1  6(4)

1 3 
1 1 3    
1 1      11(7)

3 
1 1 3    7(4)

 */

D. Minimum Steiner Tree
一句话题意:
有一棵树,给定几个点,求这几个点组成最小的树。
\(N <= 10^5\)
Analysis:
最近公共祖先入门的时候可以做的题目。
可以从一个点向祖先靠近,每一个点都打上标记,其他点也向祖先靠近的过程如果遇到标记就停下来,cnt++,记录这个过程中深度最浅的点,最后减掉这个深度。

#include<bits/stdc++.h>
using namespace std;
int n, m, dep[200005], hd[200005], f[200005], cnt , b[200005], tot;
struct Edge{
    int to, nxt;
}edge[400005];
void add(int u, int v){
    edge[++cnt].to = v;
    edge[cnt].nxt = hd[u];
    hd[u] = cnt;
}
void dfs(int u, int fa, int d){
    // cout<<u<<" "<<fa<<" "<<d<<endl;
    dep[u] = d; 
    f[u] = fa;
    for(int i = hd[u]; i; i = edge[i].nxt){
        int v = edge[i].to;
        if(v == fa) continue;
        dfs(v, u, d+1);
    }
}
int main(){
    cin>>n>>m; int x,y;
    for(int i = 1; i <= n-1; i++){
        cin>>x>>y;
        add(x,y); add(y,x);
    }
    dfs(1, 0, 1);
    cin>>x; 
    while(x != 0){//先走到根节点
        b[x] = 1;
        x = f[x];
        tot++;
    }
    // cout<<"tot: "<<tot<<endl;
    int mn = INT_MAX, p;
    for(int i = 2; i <= m; i++){
        cin>>x;
        while(b[x] != 1){
            b[x] = 1;
            tot++;
            x = f[x];
        }
        // cout<<"tot: "<<tot<<endl;
        if(dep[x] < mn) mn = dep[x];
    }
    cout<<max(1, tot - mn + 1)<<endl;
    return 0;
}

G:

[ABC368G] Add and Multiply Queries

给定两个长度为 $ N $ 的正整数序列 $ A, B $。需要处理 $ Q $ 个按顺序给出的查询。查询有以下三种类型:

  • 类型 $ 1 $:格式为 1 i x。将 $ A_i $ 替换为 $ x $。
  • 类型 $ 2 $:格式为 2 i x。将 $ B_i $ 替换为 $ x $。
  • 类型 $ 3 $:格式为 3 l r。需要解决以下问题并输出答案:
    • 初始时 $ v = 0 $。依次对 $ i = l, l + 1, \dots, r $ 进行操作,每次操作将 $ v $ 替换为 $ v + A_i $ 或 $ v \times B_i $。求最终能得到的 $ v $ 的最大值。
      需要注意的是,输入中类型 $ 3 $ 的查询的答案保证在 $ 10^{18} $ 以下。

制約

  • $ 1 \leq N \leq 10^5 $
  • $ 1 \leq A_i \leq 10^9 $
  • $ 1 \leq B_i \leq 10^9 $
  • $ 1 \leq Q \leq 10^5 $
  • 类型 $ 1 $, $ 2 $ 的查询中,$ 1 \leq i \leq N $
  • 类型 $ 1 $, $ 2 $ 的查询中,$ 1 \leq x \leq 10^9 $
  • 类型 $ 3 $ 的查询中,$ 1 \leq l \leq r \leq N $
  • 类型 $ 3 $ 的查询中,输出值在 $ 10^{18} $ 以下

类型 3 的查询的答案保证在 \(10^18\),约等于\(2^62\),也就是\(10^5\)个数字中只有60多次大于2的情况,其余情况都是1.
这样的话,我们大多数连续的区间,都是要选择A序列进行相加。
可以吧B序列中非1的位置放入set中,每次找到1的区间,树状数组求和,快速加给v。B序列单独比较非1的情况。

一开始想不明白:
1.当前询问在上一个询问基础上加减(傻X)
2.错误:没有修改:b[loc] = x;
3.错误:v = max(v+a[pos], v*b[pos]); //写成 v+= ....

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n, a[100005],b [100005], c[100005], q, op, res;
set<int> s;
int lowbit(int x){
    return x & (-x);
}
void update(int i, int x){
    while(i <= 100005){//
        c[i] += x, i += lowbit(i);
    }
}
int sum(int i){//前缀和
    int ans = 0;
    while(i){
        ans += c[i]; i -= lowbit(i);
    }
    return ans;
}
int loc, x;
signed main(){
    cin>>n;
    for(int i = 1; i <= n; i++){
        cin>>a[i]; update(i, a[i]);
    }
    for(int i = 1; i <= n; i++){
        cin>>b[i];
        if(b[i] > 1) s.insert(i);
    }
    //
    s.insert(n);
    cin>>q;
    for(int i = 1; i <= q; i++){
        cin>>op>>loc>>x;
        if(op == 1){
            update(loc, x - a[loc]);
            a[loc] = x;
        }
        else if(op == 2){
            if(b[loc] == 1){
                if(x != 1) s.insert(loc);
            }
            else{
                if(x == 1) s.erase(loc);
            }
            b[loc] = x;
        }
        else{       
            int v = a[loc++], r = x;//第一个数字一定是加到v中
            set<int>::iterator it = s.lower_bound(loc);
            while(loc <= r){
                int pos = *it;
                v += sum(min(pos-1, r)) - sum(loc-1);
                if(pos > r) break;
                v = max(v+a[pos], v*b[pos]); //写成 v+= ....
                loc = pos+1;
                it++;
            }
            cout<<v<<endl;
        }
    }
    return 0;
}
posted on 2024-08-26 17:24  Jeanny  阅读(23)  评论(0)    收藏  举报