1.并查集操作:

 1 int father[10086];
 2 int find(int x){
 3     return father[x]=(father[x]==x?x:find(father[x]));//一般都是写这个模板,因为他快,不会超时!!!
 4 }
 5 void Union(int a,int b){
 6     int f1=find(a);
 7     int f2=find(b);
 8     if(f1<f2)swap(f1,f2);//意思是大的当小的父亲,有钦定的含义在里面,这是可以自定义的额
 9     father[f2]=f1;
10 }

 2.求解最大公约数:

1 inline int gcd(int a,int b){
2     return b==0?a:gcd(b,a%b);//a一定是一直大于b的。。。
3 }

 3.

1 //priority_queue默认使用的是大顶堆:
2 priority_queue<int>pq;
3 
4 如果想使用priority_queue的小顶堆的特性,那么可以采用的是:
5 priority_queue<int,vector<int>,greater<int>()>pq;

 4.优先队列,自定义大顶堆或者小顶堆:

那个排序大于是greater<>;所以大于是小顶堆

小于是less<>,所以小于是大顶堆,一定不能弄混了。

学习链接:

1 https://blog.csdn.net/c20182030/article/details/70757660?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

比较模板,以及习题:

787. K 站中转内最便宜的航班

 1 // class Node{
 2 // public:
 3 //     Node(int _cost,int _name,int _dist):pay(_cost),name(_name),dist(_dist){}
 4 
 5 //     int pay;
 6 //     int name;
 7 //     int dist;
 8 // };
 9 struct Node{
10     int pay;
11     int name;
12     int dist;
13 };
14 
15 struct cmp{
16     //下面的含义是重载小于号的含义
17     bool operator() (Node& a,Node& b){
18         return a.pay>b.pay;
19     }
20     
21 };
22 struct edge{
23     int to;
24     int cost;
25 };
26 class Solution {
27 public:
28 //Djkstra算法,使用优先队列求解,首先写出Dijkstra算法的模板
29     int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
30         priority_queue<Node,vector<Node>,cmp>pq;//第一个参数是代价,第二个参数是到达结点位置。
31         vector<edge>g[n+1];
32         for(auto v:flights){
33             edge e;
34             e.to=v[1];
35             e.cost=v[2];
36             g[v[0]].push_back(e);
37         }
38         set<int>vis;
39         vis.clear();
40         pq.push({0,src,-1});
41         while(!pq.empty()){
42             auto x=pq.top();
43             pq.pop();
44             cout<<x.name<<" "<<vis.count(x.name)<<endl;
45             //if(vis.count(x.name))continue;
46             if(x.name==dst)return x.pay;
47             //vis.insert(x.name);
48             int n=g[x.name].size();
49             for(int i=0;i<n;i++){
50                 edge v=g[x.name][i];
51                 if(x.dist<K){
52                     pq.push({x.pay+v.cost,v.to,x.dist+1});
53                 }
54                 
55             }
56         }
57         return -1;
58     }
59 };

 Trie树模板

 1 //Trie 树
 2 #include<iostream>
 3 #include<vector>
 4 #include<string>
 5 #include<cstring>
 6 using namespace std;
 7 
 8 struct Node{
 9     Node *child[26];
10     //bool flag;
11     Node(){//构造函数
12         for(int i=0;i<26;i++){
13             child[i]=nullptr;
14         }
15     }
16 };
17 void insert(Node *root,string word){
18     Node *rt=root;//root是不能变化的,所以最初赋给一个新的值进行操作
19     for(int i=word.length()-1;i>=0;i--){
20         int to=word[i]-'a';
21         if(rt->child[to]==nullptr){
22             rt->child[to]=new Node();
23         }
24         rt=rt->child[to];
25     }
26 }
27 void count(Node *root,int &res,int deep){
28     bool flag=true;//这里涉及到递归的问题,所以需要首先设置一下,防止之后递归多加了。。。
29     for(int i=0;i<26;i++){
30         if(root->child[i]!=nullptr){
31             count(root->child[i],res,deep+1);
32             flag=false;//注意需要回溯,否则会出错。。。
33         }
34     }
35     if(flag){
36         res+=deep;//注意这里的deep需要最初多加一个,因为#也算是一部份
37         //cout<<res<<endl;
38     }
39 }
40 
41 int main(){
42     Node *root=new Node();
43     int n;
44     cin>>n;
45     string s;
46     vector<string>str;
47     for(int i=0;i<n;i++){
48         cin>>s;
49         //str.push_back(s);
50         insert(root,s);
51     }
52     int res=0;
53     count(root,res,1);
54     cout<<res<<endl;
55     return 0;
56 }
View Code

 Trie基本操作:

leetcode题目:

208. 实现 Trie (前缀树)

 1 class Trie {
 2 private:
 3     bool is_str;
 4     Trie* next[26];
 5 public:
 6     //bool is_str;//是否是一个完整的字符串
 7     /** Initialize your data structure here. */
 8     Trie() {
 9         for(int i=0;i<26;i++){
10             next[i]=nullptr;
11         }
12         is_str=false;
13     }
14     ~Trie(){//析构函数
15         for(int i=0;i<26;i++){
16             if(next[i]==nullptr)continue;
17             delete(next[i]);
18             next[i]=nullptr;
19         }
20     }
21     
22     /** Inserts a word into the trie. */
23     void insert(string word) {
24         Trie *cur=this;//将根结点this赋给给node
25         for(auto v:word){
26             if(cur->next[v-'a']==nullptr){
27                 cur->next[v-'a']=new Trie();
28             }
29             cur=cur->next[v-'a'];
30         }
31         cur->is_str=true;//表示的是这个插入的字符串是完整的。
32     }
33     
34     /** Returns if the word is in the trie. */
35     bool search(string word) {
36         Trie *cur=this;
37         for(auto v:word){
38             if(cur->next[v-'a']==nullptr)return false;
39             else cur=cur->next[v-'a'];
40         }
41         return cur->is_str;
42     }
43     
44     /** Returns if there is any word in the trie that starts with the given prefix. */
45     bool startsWith(string prefix) {
46         Trie *cur=this;
47         for(auto v:prefix){
48             if(cur->next[v-'a']==nullptr)return false;
49             else cur=cur->next[v-'a'];
50         }
51         return true;
52     }
53 
54 
55 };
View Code

 

 

最短路径算法:

743. 网络延迟时间

 1 struct edge{
 2     int to;
 3     int cost;
 4 };
 5 typedef pair<int,int>P;
 6 
 7 class Solution {
 8 public:
 9 //dijkstra算法,采用的是优先队列的小顶堆的特性,因为每一次更新会有一个结点的最短路径会最终的确定。那么下一次优先更新的是最小路径的结点。
10     int networkDelayTime(vector<vector<int>>& times, int N, int K) {
11         priority_queue<P,vector<P>,greater<P>>pq;
12         vector<edge>g[N+1];//数组中的形式是edge的格式
13         memset(dist,0x3f,sizeof(dist));
14         int n=times.size();
15         for(int i=0;i<n;i++){
16             edge e;
17             e.to=times[i][1];
18             e.cost=times[i][2];
19             g[times[i][0]].push_back(e);
20         }
21         set<int>vis;
22         pq.push({0,K});
23         int res=0;
24         while(!pq.empty()){
25             auto x=pq.top();
26             pq.pop();
27             if(vis.count(x.second))continue;
28             //vis[x.second]=true;
29             vis.insert(x.second);
30             res=max(x.first,res);
31             //cout<<res<<endl;
32             int n=g[x.second].size();
33             for(int i=0;i<n;i++){
34                 edge v=g[x.second][i];
35                 if(vis.count(v.to))continue;
36                 pq.push({v.cost+x.first,v.to});
37             }
38         }
39         return vis.size()==N?res:-1;
40     }
41 };
View Code

 

快排手写代码:

 1 void Quick_sort(int arr[],int start,int end){
 2     int i=start;
 3     int j=end;
 4     int val=arr[start];
 5     while(i<j){
 6         while(i<j&&arr[j]>=val)j--;
 7         if(i<j){
 8             arr[i]=arr[j];
 9             i++;
10         }
11         while(i<j&&arr[i]<=val)i++;
12         if(i<j){
13             arr[j]=arr[i];
14             j--;
15         }
16     }
17     arr[i]=val;
18     Quick_sort(arr,start,i-1);
19     Quick_sort(arr,i+1,end);
20 }
View Code

 二分查找模板:

1095. 山脉数组中查找目标值

 1 class Solution {
 2 public://三次二分查找,第一次找峰,第二次左边,第三次右边
 3     //不能使用暴力求解,因为get不能调用超过100次,所以只能采用二分查找的方法求解。。。。
 4     int findInMountainArray(int target, MountainArray &a) {
 5         //第一步找峰
 6         int lo=0;
 7         int hi=a.length()-1;
 8         while(lo<hi){
 9             int mid=(lo+hi)/2;
10             if(a.get(mid)<a.get(mid+1)){
11                 lo=mid+1;
12             }else{
13                 hi=mid;
14             }
15         }
16         int peak=lo;
17         cout<<peak<<endl;
18         if(target>a.get(peak))return -1;
19         int l0=0;
20         hi=peak;
21         
22         while(l0<=hi){
23             int mid=(l0+hi)/2;
24             if(a.get(mid)==target)return mid;
25             else if(a.get(mid)<target){
26                 l0=mid+1;
27             }else{
28                 hi=mid-1;
29             }
30         }
31         l0=peak;
32         hi=a.length()-1;
33         while(l0<=hi){
34             int mid=(l0+hi)/2;
35             if(a.get(mid)==target)return mid;
36             else if(a.get(mid)<target){
37                 hi=mid-1;
38             }else{
39                 l0=mid+1;
40             }
41         }
42         return -1;
43     }
44 };
View Code

 

 

KMP算法:

 1 namespace KMP{
 2     vector<int>next;//存放的是next数组
 3 
 4     void build(const string &pattern){//构建next数组
 5         int n=pattern.length();
 6         next.resize(n+1);//多构建一个位,在模式串的末尾加上一个永远不能操作的位置,方便下面匹配的操作
 7 
 8         for(int i=0,j=next[0]=-1;i<n;next[++i]=++j){
 9             while(j!=-1&&pattern[j]!=pattern[i])j=next[j];
10         }
11     }
12     vector<int>match(const string &pattern,const string &text){
13         vector<int>res;//存放的是在text中符合条件的串的初始位置。。。
14         int n=pattern.length(),m=text.length();
15         build(pattern);
16         for(int i=0,j=0;i<m;i++){
17             while(j>0&&pattern[j]!=text[i])j=next[j];//kmp主操作
18             if(pattern[j]==text[i])j++;
19             if(j==n){//表示到达最后一个位置了,表示当前位置匹配成功了
20                 res.push_back(i-n+1);
21                 j=next[j];//表示j又变成0了。。。
22             }
23         }
24     }
25 }
View Code

 

快速幂模板:

 1 typedef double db;
 2 typedef long long ll;
 3 class Solution {
 4 public:
 5     double myPow(double x, int n) {
 6         db ans=1.0;
 7         ll k=n;
 8         if(k<0){
 9             k=-k;
10             x=1/x;
11         }
12         while(k){
13             if(k&1)ans*=x;
14             x*=x;
15             k=k>>1;
16         }
17         return ans;
18     }
19 };
View Code

 

最短路径相关的代码模板:

743. 网络延迟时间

Floyd:

 1 class Solution {
 2 public:
 3     int networkDelayTime(vector<vector<int>>& times, int N, int K) {
 4         int res=0;
 5         vector<vector<int>>edge(N+1,vector<int>(N+1,0x3f3f));
 6         for(int i=1;i<=N;i++){//注意这里是从1开始的,因为我们下标是结点的值,结点值最小是1
 7             edge[i][i]=0;
 8         }
 9         for(auto v:times){
10             edge[v[0]][v[1]]=v[2];
11         }
12         for(int k=1;k<=N;k++){
13             for(int i=1;i<=N;i++){
14                 for(int j=1;j<=N;j++){
15                     edge[i][j]=min(edge[i][j],edge[i][k]+edge[k][j]);
16                 }
17             }
18         }
19         for(int i=1;i<=N;i++){
20             if(edge[K][i]==0x3f3f)return -1;//如果不能使所有结点收到信号那么返回的是-1.
21             res=max(res,edge[K][i]);
22         }
23         return res;
24 
25     }
26 };
27 
28 作者:zb121
29 链接:https://leetcode-cn.com/problems/network-delay-time/solution/cfloydspfa-by-zb121/
30 来源:力扣(LeetCode)
31 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
View Code

SPFA:

 1 class Solution {
 2 public:
 3 //SPFA解法
 4     int networkDelayTime(vector<vector<int>>& times, int N, int K) {
 5         queue<int>que;
 6         vector<vector<int>>edge(N+1,vector<int>(N+1,INT_MAX));
 7         vector<int>dist(N+1,INT_MAX);//表示的是K点到其他结点的最短距离
 8         for(auto v:times){
 9             edge[v[0]][v[1]]=v[2];
10         }
11         que.push(K);
12         dist[K]=0;
13         //SPFA使用的是队列的方式存放中间结点,方便下一次更新
14         while(!que.empty()){
15             int x=que.front();
16             que.pop();
17             for(int i=1;i<=N;i++){//只要出现有边存在,同时边长度较小,那么更新边权值。同时将其放入队列中,下一次再更新一下,当没有边需要更新的时候,那么结束吧。。。
18                 if(edge[x][i]!=INT_MAX&&dist[x]+edge[x][i]<dist[i]){
19                     dist[i]=dist[x]+edge[x][i];
20                     que.push(i);
21                 }
22             }
23         }
24         int ans=0;
25         for(int i=1;i<=N;i++){
26             if(dist[i]==INT_MAX)return -1;
27             ans=max(ans,dist[i]);
28         }
29         return ans;
30     }
31 };
32 
33 作者:zb121
34 链接:https://leetcode-cn.com/problems/network-delay-time/solution/cfloydspfa-by-zb121/
35 来源:力扣(LeetCode)
36 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
View Code

Djkstra:

 1 struct edge{
 2     int to;
 3     int cost;
 4 };
 5 typedef pair<int,int>P;
 6 
 7 class Solution {
 8 public:
 9 //dijkstra算法,采用的是优先队列的小顶堆的特性,因为每一次更新会有一个结点的最短路径会最终的确定。那么下一次优先更新的是最小路径的结点。不需要每一次更新不同结点的距离。。。
10     int networkDelayTime(vector<vector<int>>& times, int N, int K) {
11         priority_queue<P,vector<P>,greater<P>>pq;
12         vector<edge>g[N+1];//数组中的形式是edge的格式
13         int n=times.size();
14         for(int i=0;i<n;i++){
15             edge e;
16             e.to=times[i][1];
17             e.cost=times[i][2];
18             g[times[i][0]].push_back(e);
19         }
20         set<int>vis;
21         pq.push({0,K});
22         int res=0;
23         while(!pq.empty()){
24             auto x=pq.top();
25             pq.pop();
26             if(vis.count(x.second))continue;
27             vis.insert(x.second);
28             res=max(x.first,res);
29             int n=g[x.second].size();
30             for(int i=0;i<n;i++){
31                 edge v=g[x.second][i];
32                 if(vis.count(v.to))continue;
33                 pq.push({v.cost+x.first,v.to});
34             }
35         }
36         return vis.size()==N?res:-1;
37     }
38 };
39 
40 作者:zb121
41 链接:https://leetcode-cn.com/problems/network-delay-time/solution/cfloydspfa-by-zb121/
42 来源:力扣(LeetCode)
43 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
View Code

 

 

求解最长回文子串的长度:Manacher算法:

 1 //Mancher算法 ,O(n)时间复杂度解决,将奇数与偶数的回文串统一了起来!!!
 2 //HDU 3068最长回文!
 3 
 4 //核心思想:
 5 
 6 #include<iostream>
 7 #include<string>
 8 #include<algorithm>
 9 #include<cstring>
10 #include<map>
11 #include<cstdio>
12 #include<vector>
13 using namespace std;
14 const int maxn=3e5;
15 char s[maxn],str[maxn];
16 int len1,len2,p[maxn],ans;//p[i]表示的是以i为中心的回文半径是多少。。。ans存放的是最终的结果。。。
17 void init(){//这是一个完成字符串翻倍的操作,加上#实现字符串翻倍的操作。。。
18     str[0]='$';
19     str[1]='#';
20     for(int i=0;i<len1;i++){//len1是s的长度
21         str[i*2+2]=s[i];
22         str[i*2+3]='#';
23     }
24     len2=len1*2+2;//加上的2是额外的$以及*。。。
25     str[len2]='*';
26 }
27 void manacher(){
28     int id=0,mx=0;//mx是以id为中心的最长回文子串的右边界。。。
29     for(int i=1;i<len2;i++){//这里下标是1,因为i-p[i]防止越界。。。
30         if(mx>i)p[i]=min(p[2*id-i],mx-i);//这里的解释在C++程序员面试宝典上面有写,在P3.
31         else p[i]=1;
32         for(;str[i+p[i]]==str[i-p[i]];p[i]++);//暴力的匹配。。。
33         if(p[i]+i>mx){//我的串加上我的回文半径大于mx,那么更新mx
34             mx=p[i]+i;
35             id=i;//更新id
36         }
37     }
38 
39 }
40 int main(){
41     while(cin>>s){
42         //首先我们需要将string这个数组进行翻倍.init()函数完成这个功能
43         len1=strlen(s);
44         init();
45         //下面就是进行manacher的操作了。。
46         manacher();
47         ans=0;
48         for(int i=0;i<len2;i++){
49             ans=max(ans,p[i]);
50         }
51         cout<<ans-1<<endl;//因为半径其实插入了字符,所以半径就是长度二倍,所以需要减一。。。
52     }
53     return 0;
54 }
View Code

 

C11特性,基本写代码模板:

 1 #include<iostream>
 2 #include<vector>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<string>
 6 using namespace std;
 7 struct Point{
 8     int a,b;
 9     Point(int a=0,int b=0):a(a),b(b){}
10     bool operator<(const Point &rhs)const{//这样就不用再写cmp函数,重载小于运算符。
11         return a<rhs.a;
12     }
13 }
14 template <typename T1,typename T2,typename T3>//模板的使用
15 bool solve(const T1 &a,cosnt T2 &b,const T3 &c){
16 
17 }
18 
19 int main(){
20     int n=100;
21     Point ts[n];
22     sort(ts,ts+n,[](const Point& t1,cosnt Point& t2){
23         if(t1.a!=t2.a)return t1.a<t2.a;
24         return t1.b<t2.b;
25     });
26     return 0;
27 }
View Code

 

 

背包问题:

 

 1 //背包问题合集。
 2 int 0-1(){//每一个物品只能被选择一次
 3     //0-1背包
 4     int n;//n表示的是有n件物品可以选择,每一件物品有其自己的重量以及价值。
 5     int m;//m表示的是背包的总容量。
 6     vector<int>dp(n,0);//dp表示的是可以在m容量的背包中装上最大的价值是多少。
 7     vector<int>weight(n);
 8     vector<int>value(n);
 9     for(int i=1;i<=n;i++){//i表示的是物品编号。
10         for(int j=m;j>=weight[i];j--){//j表示的是容量,j从大到小就可以保证每一个物品只被选择一次。。。
11             dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);//这个j是从大到小,而j-weight[i]就是更小的,所以之后一定无法转移到大的上面。。。
12         }
13     }
14     return *max_element(dp.begin(),dp.end());
15 }
16 
17 //完全背包
18 int Wanquan(){
19     //完全背包,每一个物品可以被多次的选择。。。
20     int n,m;
21     vector<int>dp;
22     vector<int>weight;
23     vector<int>value;
24     for(int i=1;i<=n;i++){
25         for(int j=weight[i];j<=m;j++){
26             dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);//这样同一件物品i就可以被多次的选择了。因为我当前的状态可以从之前的状态转移过来。这样转移的状态选的背包可能被多次的选择。
27             //原因是j从小到大遍历的,所以之后的j-weight[i]可能是之前的状态转移的结果
28         }
29     }
30     return *max_element(dp.begin(),dp.end());
31 }
32 
33 //多重背包,是0-1背包与完全背包的结合。
34 
35 int Duochong(){
36     int n,m;
37     vector<int>dp(n,0);
38     vector<int>value;
39     vector<int>weight;
40     vector<int>num;//这个表示每一个物品的个数,这个个数不是1,当然也不是无限个,是有限制的,个数是给出来的。
41     for(int i=1;i<=n;i++){
42         for(int j=m;j>=weight[i];j--){//这样就可以保证,某一个物品是按照你的要求进行选择个数的,不会无缘无故的叠加之前的状态,从而不知道选择多少个物品。。
43             for(int k=0;k<=num[i];k++){//此时选择的个数是k个物品
44                 dp[j]=max(dp[j],dp[j-k*weight[i]]+k*value[i]);
45             }
46         }
47     }
48     return *max_element(dp.begin(),dp.end());
49 }
View Code

 

 

线段树模板:

  1 //树状数组主要处理的是一个数组中更新每一个区段数组的值,求每一个区段数组的和,或者某一段数组的最大值。。。
  2 //线段树。。。
  3 
  4 
  5 // const int maxn=1e6+5;
  6 // typedef long long ll
  7 // //vector<int>a(maxn,0);
  8 // int n,q
  9 // int sum[maxn<<2];
 10 // int a[maxn];
 11 // void push_up(int rt){
 12 //     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 13 // }
 14 // void build(int l,int r,int rt){//首先建一颗线段树,rt表示的是当前的结点是多少。。。l,r是范围大小
 15 //     sum[rt]=0;
 16 //     if(l==r){
 17 //         sum[rt]=a[l];
 18 //     }
 19 //     int mid=(l+r)>>1;
 20 //     build(l,mid,rt<<1);
 21 //     build(mid+1,r,rt<<1|1);
 22 //     push_up(rt);//就是将两个叶子结点的值传上去。。。
 23 // }
 24 // void update(int pos,int val,int l,int r,int rt){//就是更新pos位置的结点值为val...l,r为范围,rt为当前的结点
 25 
 26 
 27 // }
 28 
 29 // int main(){
 30 
 31 //     return 0;
 32 // }
 33 
 34 
 35 
 36 
 37 // const int maxn=1e5+5;
 38 // int sum[maxn<<2];
 39 
 40 // int a[maxn];//表示当前结点存在的数组中。。。
 41 
 42 // void push_up(int rt){
 43 //     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 44 // }
 45 
 46 // void build(int l,int r,int rt){//rt当前结点位置,就是当前的根。。。
 47 //     sum[rt]=0;
 48 //     if(l==r){
 49 //         sum[rt]=a[l];//表示到达最底下的叶子结点
 50 //         return;
 51 //     }
 52 //     int mid=(l+r)>>1;
 53 //     build(l,mid,rt<<1);//找根结点的左儿子
 54 //     build(mid+1,r,rt<<1|1);
 55 //     push_up(rt);
 56 // }
 57 
 58 // //求解一个区间的sum值,写一个函数query
 59 // int query(int L,int R,int l,int r,int rt){//我需要查询的区间是[L,R],我当前的区间是(l,r),当前的结点是rt
 60 //     if(L<=l&&R>=r){
 61 //         //这个含义是:我所递归到的区间,在我查询区间的里面,那么这个低估区间当前的结点的sum值直接返回,因为这个值一定是所需要的,不需要再往下做无用的查询了。。。
 62 //         return sum[rt];
 63 //     }
 64 //     int ans=0;
 65 //     int mid=(l+r)>>1;
 66 //     if(L<=mid){
 67 //         ans+=query(L,R,l,mid,rt<<1);
 68 //     }
 69 //     if(R>mid){
 70 //         ans+=query(L,R,mid+1,r,rt<<1|1);
 71 //     }
 72 //     return ans;
 73 // }
 74 
 75 // void update(int L,int R,int val,int l,int r,int rt){//全部使用区间修改的方法,修改区间为[L,R]
 76 //     if(L<=l&&R>=r){
 77 //         sum[rt]+=val;
 78 //         return;
 79 //     }
 80 //     int mid=(l+r)>>1;
 81 //     if(L<=mid){
 82 //         update(L,R,val,l,mid,rt<<1);
 83 //     }
 84 //     if(R>mid){
 85 //         update(L,R,val,mid+1,r,rt<<1|1);
 86 //     }
 87 //     push_up(rt);
 88 // }
 89 
 90 // int main(){
 91 //     int n,q;
 92 //     cin>>n;
 93 //     for(int i=1;i<=n;i++){
 94 //         cin>>a[i];
 95 //     }
 96 //     build(1,n,1);
 97 //     int m;
 98 //     // int ans=query(1,n,1,n,1);
 99 //     // cout<<ans<<endl;
100 //     cin>>m;
101 //     for(int i=0;i<m;i++){
102 //         int l,r,v;
103 //         cin>>l>>r>>v;
104 //         update(l,r,v,1,n,1);
105 //         cout<<"Ok"<<endl;
106 //         int ans=query(1,n,1,n,1);
107 //         cout<<ans<<endl;
108 //     }
109 
110 // }
111 //线段树模板:
112 #include<iostream>
113 #include<cstdio>
114 #include<algorithm>
115 #include<vector>
116 using namespace std;
117 
118 const int maxn=1e5+10;
119 typedef long long ll;
120 
121 int a[maxn];
122 
123 struct node{
124     int l,r;
125     ll sum,lazy;//lazy的意思就是有的时候区间更改,只需要改需要修改的一段区间,eg.[1,3]只需修改范围为[1,3]的结点,下面的结点不需要修改,因为你之后不需要访问下面的结点内容的,下面的区间是不需要修改的。。。
126     void update(ll x){
127         sum+=1ll*(r-l+1)*x;
128         lazy+=x;
129     }
130 }tree[maxn<<2];
131 
132 void push_up(int x){
133     tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;//做儿子和与右儿子的和。。。
134 }
135 
136 void push_down(int x){
137     int lazyval=tree[x].lazy;
138     if(lazyval){
139         tree[x<<1].update(lazyval);
140         tree[x<<1|1].update(lazyval);
141         tree[x].lazy=0;
142     }
143 }
144 
145 void build(int x,int l,int r){//x是当前结点的编号。。。l,r是区间范围
146     tree[x].l=l;
147     tree[x].r=r;
148     tree[x].sum=tree[x].lazy=0;
149     if(l==r){
150         tree[x].sum=a[l];
151         return ;
152     }else{
153         int mid=(l+r)>>1;
154         build(x<<1,l,mid);
155         build(x<<1|1,mid+1,r);
156         push_up(x);
157     }
158 }
159 
160 void update(int x,int l,int r,ll val){//注意这里的l,r是需要更新的范围
161     int L=tree[x].l,R=tree[x].r;//这个L,R是结点当前的[L,R]管辖的范围
162     if(l<=L&&r>=R){//直接更新
163         tree[x].update(val);
164         return;
165     }else{
166         //先将信息传下去
167         push_down(x);
168         int mid=(L+R)>>1;
169         if(mid>=l){
170             update(x<<1,l,r,val);//注意这个是l,r表示的是需要查找的范围。。。这个需要查找的范围是不能够改变的。。。
171         }
172         if(r>mid){
173             update(x<<1|1,l,r,val);
174         }
175         push_up(x);
176     }
177 }
178 
179 ll query(int x,int l,int r){
180     int L=tree[x].l,R=tree[x].r;
181     if(l<=L&&R<=r){//x的区间都是从到小的if
182         return tree[x].sum;
183     }else{
184         push_down(x);//需要查询某一个区间先push_down一下,这一步一定要有,因为有肯能之前更新的时候,需要查询的这一段区间没有更新,但是现在需要查询这一段了,那么我们一定要先更新一下,然后再进行查询操作。。。
185         ll ans=0;
186         int mid=(L+R)>>1;
187         if(mid>=l){
188             ans+=query(x<<1,l,r);
189         }
190         if(mid<r){
191             ans+=query(x<<1|1,l,r);
192         }
193         push_up(x);
194         return ans;
195     }
196 }
197 
198 int main(){
199     int n;
200     scanf("%d",&n);
201     for(int i=1;i<=n;i++){
202         scanf("%d",&a[i]);
203     }
204     build(1,1,n);
205     int m;
206     scanf("%d",&m);
207     for(int i=0;i<m;i++){
208         int l,r,v;
209         scanf("%d%d%d",&l,&r,&v);
210         update(1,l,r,v);
211         printf("%lld\n",query(1,l,r));
212     }
213     return 0;
214 }
View Code

 

 

石子合并:virtual judge搜一下题目/洛谷P1880

直线问题:

 1 //直线问题:
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<string>
 6 #include<vector>
 7 #include<cmath>
 8 #include<map>
 9 #include<cstdlib>
10 #include<sstream>
11 #include<set>
12 #include<queue>
13 using namespace std;
14 typedef long long ll;
15 typedef pair<int,int>PII;
16 typedef pair<ll,ll>PLL;
17 #define make_pair mkp;
18 
19 int dp1[400][400];//求解最小值的,,,,
20 int dp2[441][441];//求解最大值得。。。
21 int a[441];
22 int sum[441];
23 int main(){
24     int n;
25     //while(cin>>n){
26     cin>>n;
27         memset(dp1,0x3f,sizeof(dp1));
28         memset(dp2,-1,sizeof(dp2));
29         for(int i=1;i<=n;i++){
30             cin>>a[i];
31         }
32         memset(sum,0,sizeof(sum));
33         //sum[0]=a[0];
34         for(int i=1;i<=n;i++){
35             sum[i]=sum[i-1]+a[i];//求解前缀和。。。
36             //cout<<sum[i]<<endl;
37         }
38         for(int i=1;i<=n;i++){
39             dp1[i][i]=0;
40             dp2[i][i]=0;
41         }
42         for(int len=1;len<n;len++){
43             for(int i=1;i+len<=n;i++){
44                 int j=i+len;
45                 //dp1[i][j]=1e9;
46                 for(int k=i;k<j;k++){
47                     dp1[i][j]=min(dp1[i][j],dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]);//当前以k为分割点进行分割求解。。。
48                     dp2[i][j]=max(dp2[i][j],dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]);
49                 }
50             }
51         }
52         cout<<dp1[1][n]<<endl;
53         cout<<dp2[1][n]<<endl;
54     //}
55 
56 
57     return 0;
58 }
View Code

曲线问题:

 1 //曲线问题石子合并
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<string>
 6 #include<cstring>
 7 #include<numeric>
 8 #include<vector>
 9 #include<map>
10 #include<queue>
11 #include<set>
12 #include<cmath>
13 using namespace std;
14 typedef long long ll;
15 typedef pair<int,int>PII;
16 typedef pair<ll,ll>PLL;
17 
18 //这一题是石子合并问题的延伸版本。。。注意一定不要忘记去环的情况。。。
19 
20 //注意与直线是类似的,只不过是将环展开就完事了。。。
21 int dp1[450][450];//求解最小值
22 int dp2[400][450];//求解最大值
23 int sum[450];//维护一个前缀和。。。
24 int a[450];
25 int main(){
26     int n;
27     //while(cin>>n){
28         cin>>n;
29         memset(dp1,0x3f,sizeof(dp1));
30         memset(dp2,-1,sizeof(dp2));
31         memset(sum,0,sizeof(sum));
32         for(int i=1;i<=n;i++){
33             cin>>a[i];
34         }
35         for(int i=1;i<=n;i++){
36             a[i+n]=a[i];
37         }
38         for(int i=1;i<=n*2;i++){
39             dp1[i][i]=0;
40             dp2[i][i]=0;
41             sum[i]=sum[i-1]+a[i];//求解前缀和。。。
42         }
43         for(int len=1;len<=n;len++){
44             for(int i=1;i+len<=2*n;i++){
45                 int j=i+len;
46                 for(int k=i;k<j;k++){
47                     dp1[i][j]=min(dp1[i][j],dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]);
48                     dp2[i][j]=max(dp2[i][j],dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]);
49                 }
50             }
51         }
52         int res1=1e9;
53         int res2=-1;
54         for(int i=1;i<=n;i++){
55             res1=min(res1,dp1[i][i+n-1]);
56             res2=max(res2,dp2[i][i+n-1]);
57         }
58         cout<<res1<<endl;
59         //cout<<res2<<endl;
60     //}
61     return 0;
62 }
View Code